Je trouve la réponse de Lasse sur le blog de Chris Storms une excellente explication.
J'espère que cela ne les dérange pas que je copie le contenu.
C'est une belle explication des champs finaux, mais cela n'explique pas vraiment les constructeurs const. Rien dans ces exemples n'utilise réellement que les constructeurs sont des constructeurs const. Toute classe peut avoir des champs finaux, constructeurs const ou non.
Un champ dans Dart est en réalité un emplacement de stockage anonyme combiné avec un getter et un setter créés automatiquement qui lit et met à jour le stockage, et il peut également être initialisé dans la liste d'initialisation d'un constructeur.
Un champ final est le même, juste sans le setter, donc la seule façon de définir sa valeur est dans la liste d'initialisation du constructeur, et il n'y a aucun moyen de changer la valeur après cela - d'où le "final".
Le but des constructeurs const n'est pas d'initialiser les champs finaux, n'importe quel constructeur génératif peut le faire. Le but est de créer des valeurs constantes au moment de la compilation: des objets où toutes les valeurs de champ sont déjà connues au moment de la compilation, sans exécuter aucune instruction.
Cela met quelques restrictions sur la classe et le constructeur. Un constructeur const ne peut pas avoir de corps (aucune instruction exécutée!) Et sa classe ne doit pas avoir de champs non finaux (la valeur que nous "connaissons" au moment de la compilation ne doit pas pouvoir changer plus tard). La liste d'initialisation doit également initialiser les champs uniquement avec d'autres constantes au moment de la compilation, de sorte que les côtés droits sont limités aux "expressions de constante au moment de la compilation" [1]. Et il doit être précédé de "const" - sinon, vous obtenez juste un constructeur normal qui satisfait à ces exigences. C'est parfaitement bien, ce n'est tout simplement pas un constructeur const.
Afin d'utiliser un constructeur const pour créer réellement un objet constant au moment de la compilation, vous remplacez alors "new" par "const" dans une "new" -expression. Vous pouvez toujours utiliser "new" avec un constructeur const, et il créera toujours un objet, mais ce sera juste un nouvel objet normal, pas une valeur constante à la compilation. Autrement dit: un constructeur const peut également être utilisé comme constructeur normal pour créer des objets au moment de l'exécution, ainsi que pour créer des objets constants au moment de la compilation au moment de la compilation.
Donc, à titre d'exemple:
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!
}
Les constantes au moment de la compilation sont canonisées. Cela signifie que peu importe le nombre de fois que vous écrivez "const Point (0,0)", vous ne créez qu'un seul objet. Cela peut être utile - mais pas autant qu'il n'y paraît, car vous pouvez simplement créer une variable const pour contenir la valeur et utiliser la variable à la place.
Alors, à quoi servent les constantes de compilation?
- Ils sont utiles pour les énumérations.
- Vous pouvez utiliser des valeurs constantes au moment de la compilation dans les cas de commutation.
- Ils sont utilisés comme annotations.
Les constantes au moment de la compilation étaient plus importantes avant que Dart ne passe à l'initialisation paresseuse des variables. Avant cela, vous ne pouviez déclarer qu'une variable globale initialisée comme "var x = foo;" si "foo" était une constante de compilation. Sans cette exigence, la plupart des programmes peuvent être écrits sans utiliser d'objets const
Donc, bref résumé: les constructeurs Const sont juste pour créer des valeurs constantes au moment de la compilation.
/ L
[1] Ou vraiment: "Potentiellement des expressions constantes au moment de la compilation" car cela peut aussi faire référence aux paramètres du constructeur. [2] Donc oui, une classe peut avoir à la fois des constructeurs const et non const.