Trovo che la risposta di Lasse sul blog di Chris Storms sia un'ottima spiegazione.
Spero che a loro non dispiaccia che copio il contenuto.
Questa è una bella spiegazione dei campi finali, ma in realtà non spiega i costruttori const. Niente in questi esempi utilizza effettivamente il fatto che i costruttori siano costruttori const. Ogni classe può avere campi finali, costruttori const o meno.
Un campo in Dart è in realtà una posizione di archiviazione anonima combinata con un getter e un setter creati automaticamente che legge e aggiorna l'archiviazione e può anche essere inizializzato nell'elenco di inizializzatori di un costruttore.
Un campo finale è lo stesso, solo senza il setter, quindi l'unico modo per impostare il suo valore è nell'elenco degli inizializzatori del costruttore, e non c'è modo di cambiare il valore dopo di che - da qui il "finale".
Lo scopo dei costruttori const non è inizializzare i campi finali, qualsiasi costruttore generativo può farlo. Il punto è creare valori costanti in fase di compilazione: oggetti in cui tutti i valori dei campi sono noti già in fase di compilazione, senza eseguire alcuna istruzione.
Ciò pone alcune limitazioni alla classe e al costruttore. Un costruttore const non può avere un corpo (nessuna istruzione eseguita!) E la sua classe non deve avere campi non finali (il valore che "conosciamo" in fase di compilazione non deve essere in grado di cambiare in seguito). L'elenco degli inizializzatori deve anche inizializzare solo i campi su altre costanti in fase di compilazione, quindi i lati di destra sono limitati a "espressioni costanti in fase di compilazione" [1]. E deve essere preceduto da "const", altrimenti si ottiene solo un normale costruttore che soddisfa tali requisiti. Va benissimo, semplicemente non è un costruttore const.
Per utilizzare un costruttore const per creare effettivamente un oggetto costante in fase di compilazione, sostituire "new" con "const" in una "nuova" espressione. Puoi ancora usare "new" con un costruttore const, e creerà ancora un oggetto, ma sarà solo un normale nuovo oggetto, non un valore costante del tempo di compilazione. Ovvero: un costruttore const può essere utilizzato anche come un normale costruttore per creare oggetti in fase di esecuzione, oltre a creare oggetti costanti in fase di compilazione in fase di compilazione.
Quindi, ad esempio:
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!
}
Le costanti in fase di compilazione sono canonizzate. Ciò significa che non importa quante volte scrivi "const Point (0,0)", crei solo un oggetto. Potrebbe essere utile, ma non quanto sembrerebbe, poiché puoi semplicemente creare una variabile const per contenere il valore e utilizzare invece la variabile.
Allora, a cosa servono comunque le costanti in fase di compilazione?
- Sono utili per le enumerazioni.
- È possibile utilizzare i valori delle costanti del tempo di compilazione nei casi di switch.
- Sono usati come annotazioni.
Le costanti in fase di compilazione erano più importanti prima che Dart passasse all'inizializzazione pigra delle variabili. Prima di allora, potevi solo dichiarare una variabile globale inizializzata come "var x = foo;" se "foo" fosse una costante del tempo di compilazione. Senza questo requisito, la maggior parte dei programmi può essere scritta senza utilizzare alcun oggetto const
Quindi, breve sommario: i costruttori Const servono solo per creare valori di costanti in fase di compilazione.
/ L
[1] O in realtà: "Espressioni di costanti del tempo di compilazione potenzialmente" perché può anche fare riferimento ai parametri del costruttore. [2] Quindi sì, una classe può avere contemporaneamente costruttori const e non const.