La keyword late e la sicurezza dei valori null
Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 26 di 110.
A volte ti serve una variabile non nullable, ma non puoi assegnarle subito un valore. La parola chiave late dice a Dart: «Prometto di inizializzarla prima di usarla».
late String description;
void setup() {
description = 'Initialized later';
}
void main() {
setup();
print(description); // Funziona - inizializzata prima dell'uso
}Senza late, Dart segnalerebbe che description non è inizializzato. Con late, ti assumi la responsabilità di assicurarti che abbia un valore prima di accedervi. Se provi a leggerlo prima dell'inizializzazione, otterrai un errore in fase di esecuzione.
Un caso d'uso comune riguarda i calcoli costosi che vuoi rimandare fino a quando non sono effettivamente necessari:
class DataProcessor {
late List<int> data = _loadData();
List<int> _loadData() {
print('Loading data...');
return [1, 2, 3, 4, 5];
}
}
DataProcessor processor = DataProcessor();
// 'Loading data...' aún no se ha mostrado
print(processor.data); // Ahora carga los datos y los muestraIl metodo _loadData() viene eseguito solo quando si accede per la prima volta a data, non quando viene creato l’oggetto. Questa inizializzazione differita può migliorare le prestazioni quando il valore potrebbe non essere mai necessario.
Usa late quando sei certo che una variabile verrà inizializzata prima dell'uso, ma non puoi farlo al momento della dichiarazione. È una promessa al compilatore: se non la mantieni, il programma si arresta in modo anomalo.
Sfida
FacileCostruiamo un gestore della configurazione che dimostri la potenza delle variabili late per l’inizializzazione differita. Creerai un sistema in cui le operazioni di configurazione costose vengono eseguite solo quando la configurazione è effettivamente necessaria.
Organizzerai il codice in due file:
config_manager.dart: definisci una classeConfigManagerche gestisce le impostazioni dell’applicazione. La classe dovrebbe avere:- Un
String appNamepassato tramite il costruttore - Un
late String databaseUrlche verrà inizializzato in seguito tramite un metodo di configurazione - Un
late int maxConnectionscon inizializzazione lazy che stampaCalculating max connections...al primo accesso e restituisce100 - Un metodo
setupDatabase(String url)che inizializzadatabaseUrl - Un metodo
displayConfig()che stampa la configurazione corrente
- Un
main.dart: importa il gestore della configurazione e mostra come funzionano le variabili late:- Crea un
ConfigManagercon il nome dell’app'MyApp' - Stampa
Config created - Chiama
setupDatabasecon l’URL'localhost:5432/mydb' - Stampa
Accessing max connections... - Stampa il valore di
maxConnections - Stampa
Accessing max connections again... - Stampa di nuovo il valore di
maxConnections(nota che il messaggio di calcolo non viene ripetuto) - Chiama
displayConfig()
- Crea un
Il metodo displayConfig() dovrebbe stampare nel seguente formato:
--- Configuration ---
App: [appName]
Database: [databaseUrl]
Max Connections: [maxConnections]Nota come il calcolo lazy di maxConnections venga eseguito una sola volta, al primo accesso. Questo è il vantaggio di late con un inizializzatore!
Output previsto:
Config created
Accessing max connections...
Calculating max connections...
100
Accessing max connections again...
100
--- Configuration ---
App: MyApp
Database: localhost:5432/mydb
Max Connections: 100Provalo tu
import 'config_manager.dart';
void main() {
// TODO: Crea un ConfigManager con il nome dell'app 'MyApp'
// TODO: Stampa 'Config created'
// TODO: Chiama setupDatabase con l'URL 'localhost:5432/mydb'
// TODO: Stampa 'Accessing max connections...'
// TODO: Stampa il valore di maxConnections
// TODO: Stampa 'Accessing max connections again...'
// TODO: Stampa di nuovo il valore di maxConnections
// (nota che il messaggio di calcolo non viene ripetuto)
// TODO: Chiama displayConfig()
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniLibrerie e importazioniIntroduzione alla programmazione orientata agli oggettiClassi e oggettiLa parola chiave thisMetodiVariabili di istanzaFondamenti dei costruttoriRiepilogo - Calcolatrice semplice4Sicurezza dei valori null
Introduzione alla sicurezza dei valori nullNullable e non nullableGli operatori ? e !La keyword late e la sicurezza dei valori nullOperatori null-awareSicurezza dei valori null nelle classiRiepilogo - Sistema di profili utente7Classi astratte e interfacce
Classi astratteMetodi astrattiInterfacce in DartInterfacce impliciteImplementare vs estendereInterfacce multipleRiepilogo - Calcolatore di forme10Collezioni e generici
Panoramica di List, Set e MapCollezioni sicure rispetto ai tipiClassi genericheMetodi genericiVincoli sui genericiIterable e IteratorRiepilogo - Archiviazione generica13Concetti avanzati di OOP
Composizione vs ereditarietàMetodi di estensioneClassi chiamabiliClassi sealed (Dart 3)Record (Dart 3)Pattern e matching (3.0)Enum con metodi16Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e Utente2I costruttori in Dart
Costruttore predefinitoCostruttori con nomeListe di inizializzazioneCostruttori costantiCostruttori factoryCostruttori di reindirizzamentoRiepilogo - Crea forme5Incapsulamento
Membri pubblici e privatiConvenzione del prefisso _Visibilità a livello di libreriaApprofondimento su getter e setterNascondimento delle informazioniRiepilogo - Registri degli studenti8Mixin
Introduzione ai MixinCreare MixinUsare più MixinParola chiave on nei MixinMixin vs ereditarietàMixin vs interfacciaRiepilogo - Sistema animale11Metodi speciali
Sovrascrittura di toString()Sovrascrittura di hashCode e ==Interfaccia ComparableMetodo call()Sovrascrittura di noSuchMethodRiepilogo - Collezione personalizzata14Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneSingletonFactoryObserverStrategy3Proprietà delle classi
Membri di istanza e staticiCampi final e constVariabili lateMetodi e campi staticiGetter e setterRiepilogo - Gestore di conti bancari6Ereditarietà
Ereditarietà di baseLa parola chiave superOverride dei metodiL’annotazione @overrideLa parola chiave final per le classiCostruttori ed ereditarietàRiepilogo - Gerarchia dei dipendenti9Polimorfismo
Fondamenti di polimorfismoPolimorfismo tramite interfacceControllo del tipo a runtimeGli operatori is e asParola chiave covariantRiepilogo - Elaboratore di pagamenti12OOP asincrona
Future e async/awaitNozioni di base sugli streamController degli streamCostruttori asincroniAsync nei metodi di classeRiepilogo - Recupero dei dati15Pattern di progettazione Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositePattern RepositoryEsercitati da solo: Compilatore Dart online