Ich finde Masses Antwort auf Chris Storms Blog eine großartige Erklärung.
Ich hoffe, es macht ihnen nichts aus, dass ich den Inhalt kopiere.
Dies ist eine gute Erklärung für die letzten Felder, aber es erklärt nicht wirklich const-Konstruktoren. Nichts in diesen Beispielen verwendet tatsächlich, dass die Konstruktoren const-Konstruktoren sind. Jede Klasse kann endgültige Felder, const-Konstruktoren oder nicht haben.
Ein Feld in Dart ist in Wirklichkeit ein anonymer Speicherort in Kombination mit einem automatisch erstellten Getter und Setter, der den Speicher liest und aktualisiert. Er kann auch in der Initialisierungsliste eines Konstruktors initialisiert werden.
Ein letztes Feld ist dasselbe, nur ohne den Setter. Die einzige Möglichkeit, seinen Wert festzulegen, besteht in der Konstruktorinitialisiererliste, und es gibt keine Möglichkeit, den Wert danach zu ändern - daher das "endgültige".
Der Sinn von const-Konstruktoren besteht nicht darin, endgültige Felder zu initialisieren. Jeder generative Konstruktor kann dies tun. Es geht darum, Konstantenwerte zur Kompilierungszeit zu erstellen: Objekte, bei denen alle Feldwerte bereits zur Kompilierungszeit bekannt sind, ohne dass Anweisungen ausgeführt werden.
Das schränkt die Klasse und den Konstruktor ein. Ein const-Konstruktor kann keinen Body haben (keine Anweisungen ausgeführt!) Und seine Klasse darf keine nicht endgültigen Felder haben (der Wert, den wir zur Kompilierungszeit "kennen", darf sich später nicht ändern können). Die Initialisierungsliste darf auch Felder nur mit anderen Konstanten zur Kompilierungszeit initialisieren, sodass die rechten Seiten auf "Konstantenausdrücke zur Kompilierungszeit" beschränkt sind [1]. Und es muss "const" vorangestellt werden - andernfalls erhalten Sie nur einen normalen Konstruktor, der diese Anforderungen erfüllt. Das ist vollkommen in Ordnung, es ist einfach kein const-Konstruktor.
Um einen const-Konstruktor zu verwenden, um tatsächlich ein Konstantenobjekt zur Kompilierungszeit zu erstellen, ersetzen Sie "new" in einem "new" -Ausdruck durch "const". Sie können "new" weiterhin mit einem const-Konstruktor verwenden, und es wird weiterhin ein Objekt erstellt, es handelt sich jedoch nur um ein normales neues Objekt und nicht um einen konstanten Wert zur Kompilierungszeit. Das heißt: Ein const-Konstruktor kann auch als normaler Konstruktor verwendet werden, um Objekte zur Laufzeit sowie konstante Objekte zur Kompilierungszeit zur Kompilierungszeit zu erstellen.
Also als Beispiel:
class Point {
static final Point ORIGIN = const Point(0, 0);
final int x;
final int y;
const Point(this.x, this.y);
Point.clone(Point other): x = other.x, y = other.y; //[2]
}
main() {
// Assign compile-time constant to p0.
Point p0 = Point.ORIGIN;
// Create new point using const constructor.
Point p1 = new Point(0, 0);
// Create new point using non-const constructor.
Point p2 = new Point.clone(p0);
// Assign (the same) compile-time constant to p3.
Point p3 = const Point(0, 0);
print(identical(p0, p1)); // false
print(identical(p0, p2)); // false
print(identical(p0, p3)); // true!
}
Konstanten zur Kompilierungszeit werden kanonisiert. Das heißt, egal wie oft Sie "const Point (0,0)" schreiben, Sie erstellen nur ein Objekt. Das mag nützlich sein - aber nicht so viel, wie es scheint, da Sie einfach eine const-Variable erstellen können, die den Wert enthält, und stattdessen die Variable verwenden.
Wofür sind Konstanten zur Kompilierungszeit überhaupt gut?
- Sie sind nützlich für Aufzählungen.
- In Switch-Fällen können Sie Konstantenwerte zur Kompilierungszeit verwenden.
- Sie werden als Anmerkungen verwendet.
Konstanten zur Kompilierungszeit waren früher wichtiger, bevor Dart auf träge Initialisierung von Variablen umstellte. Vorher konnten Sie nur eine initialisierte globale Variable wie "var x = foo;" deklarieren. wenn "foo" eine Kompilierungszeitkonstante war. Ohne diese Anforderung können die meisten Programme ohne Verwendung von const-Objekten geschrieben werden
Kurze Zusammenfassung: Const-Konstruktoren dienen nur zum Erstellen von Konstantenwerten zur Kompilierungszeit.
/ L.
[1] Oder wirklich: "Konstante Ausdrücke zur Kompilierungszeit", da sie sich möglicherweise auch auf die Konstruktorparameter beziehen. [2] Ja, eine Klasse kann gleichzeitig sowohl const- als auch non-const-Konstruktoren haben.