Introduzione alla sicurezza dei valori null
Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 23 di 110.
Una delle fonti più comuni di bug nella programmazione è tentare di usare un valore che non esiste. In Dart, questa speciale «assenza di valore» è rappresentata da null. La funzionalità di sicurezza rispetto a null di Dart ti aiuta a individuare questi errori prima ancora che il tuo codice venga eseguito.
Senza la sicurezza rispetto ai valori null, qualsiasi variabile potrebbe potenzialmente essere null, causando arresti anomali durante l'esecuzione quando provi a usarla:
// Nelle versioni precedenti di Dart (senza null safety)
String name; // Potrebbe essere null!
print(name.length); // Si verifica un errore se name è nullCon null safety attivata (Dart 2.12+), il compilatore distingue tra le variabili che possono contenere null e quelle che non possono. Per impostazione predefinita, le variabili sono non annullabili: devono sempre contenere un valore valido:
String name = 'Alice'; // Deve avere un valore
print(name.length); // Sicuro: name non è mai nullIl compilatore si rifiuterà di compilare il codice in cui una variabile non nullable potrebbe essere null. Questo sposta il rilevamento degli errori dal runtime al momento della compilazione, rendendo i tuoi programmi più affidabili. Nelle prossime lezioni imparerai a dichiarare tipi nullable quando ne hai davvero bisogno e gli operatori che Dart mette a disposizione per lavorare in sicurezza con valori potenzialmente nulli.
Sfida
FacileCostruiamo un semplice sistema di schede contatto che dimostri l'importanza delle variabili non nullable. Creerai un sistema in cui ogni contatto deve avere informazioni valide e garantite.
Organizzerai il codice in due file:
contact.dart: Definisci una classeContactche rappresenti le informazioni di contatto di una persona. Poiché stiamo lavorando con la null safety, ogni campo deve avere un valore valido: non sono ammessi dati mancanti! La tua classe dovrebbe avere:- Un
String firstNameper il nome del contatto - Un
String lastNameper il cognome del contatto - Un
String emailper l'indirizzo email del contatto - Un
int phoneDigitsper il numero di cifre del numero di telefono - Un costruttore che accetta tutti e quattro i valori
- Un getter
fullNameche restituisce il nome e il cognome uniti, con uno spazio tra loro - Un metodo
displayCard()che stampa le informazioni del contatto
- Un
main.dart: Importa la tua classe di contatto e crea due contatti per dimostrare che tutti i campi hanno sicuramente un valore:- Crea un contatto con nome
'Emma', cognome'Wilson', email'emma@mail.com'e numero di cifre del telefono10 - Crea un contatto con nome
'James', cognome'Brown', email'james@work.com'e numero di cifre del telefono11 - Chiama
displayCard()su ciascun contatto nell'ordine indicato sopra
- Crea un contatto con nome
Il metodo displayCard() dovrebbe stampare esattamente nel seguente formato:
--- Contact Card ---
Name: [fullName]
Email: [email]
Phone digits: [phoneDigits]Nota come ogni variabile debba essere inizializzata con un valore reale: questa è la null safety in azione! Il compilatore garantisce che, quando accedi a fullName, email o a qualsiasi altro campo, questo conterrà sempre dati validi.
Risultato atteso:
--- Contact Card ---
Name: Emma Wilson
Email: emma@mail.com
Phone digits: 10
--- Contact Card ---
Name: James Brown
Email: james@work.com
Phone digits: 11Provalo tu
import 'contact.dart';
void main() {
// TODO: Crea il primo contatto con:
// - nome: 'Emma'
// - cognome: 'Wilson'
// - email: 'emma@mail.com'
// - cifre del numero di telefono: 10
// TODO: Crea il secondo contatto con:
// - nome: 'James'
// - cognome: 'Brown'
// - email: 'james@work.com'
// - cifre del numero di telefono: 11
// TODO: Chiama displayCard() su ogni contatto, nell'ordine
}
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