Nullable vs Non-Nullable
Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 24 sur 110.
Maintenant que vous comprenez pourquoi la sécurité contre les valeurs nulles (null safety) est importante, voyons comment déclarer des variables qui peuvent contenir null. En Dart, vous rendez un type nullable en ajoutant un ? après le nom du type.
String name = 'Alice'; // Non-nullable - doit toujours avoir une valeur
String? nickname; // Nullable - peut être null ou une String
print(name); // Alice
print(nickname); // nullLa différence clé est que les types non-nullables garantissent qu'une valeur existe, tandis que les types nullables permettent explicitement l'absence de valeur. Cette distinction s'applique à tous les types :
int count = 10; // Doit avoir une valeur
int? optionalCount; // Peut être nul
List<String> items = []; // Doit être une liste (peut être vide)
List<String>? maybeItems; // Pourrait être nul (pas de liste du tout)Notez qu'une liste vide [] est différente de null. Une liste vide existe mais ne contient rien ; null signifie qu'aucune liste n'existe du tout.
Le compilateur applique ces règles strictement. Vous ne pouvez pas assigner null à une variable non-nullable, et vous ne pouvez pas utiliser une variable nullable là où une variable non-nullable est attendue sans avoir préalablement vérifié la présence de null :
String? maybeName = 'Bob';
// String definite = maybeName; // Erreur ! Impossible d'assigner une valeur nullable à une valeur non-nullableDans la prochaine leçon, vous apprendrez les opérateurs que Dart fournit pour travailler en toute sécurité avec des valeurs nullables.
Défi
FacileConstruisons un système de liste de films à voir qui démontre la différence entre les informations obligatoires et les informations facultatives en utilisant des types nullables et non-nullables.
Vous allez créer deux fichiers pour organiser votre code :
movie.dart: Définissez une classeMoviequi représente un film dans votre liste. Chaque film doit avoir un titre et une année de sortie (ceux-ci sont toujours obligatoires), mais certains détails supplémentaires pourraient ne pas être disponibles pour chaque film. Votre classe doit avoir :- Un
String titlenon-nullable - chaque film doit avoir un titre - Un
int yearnon-nullable - chaque film doit avoir une année de sortie - Un
String? directornullable - le réalisateur peut être inconnu - Un
double? ratingnullable - tous les films n'ont pas encore été évalués - Un constructeur qui prend
titleetyearcomme paramètres obligatoires - Une méthode
displayInfo()qui affiche les informations du film, en affichant"Unknown"pour un réalisateur manquant et"Not rated"pour une évaluation manquante
- Un
main.dart: Importez votre classe de film et créez une petite liste de films démontrant à la fois des données de film complètes et incomplètes :- Créez un film avec le titre
'Inception'et l'année2010, puis définissez son réalisateur sur'Christopher Nolan'et sa note sur8.8 - Créez un film avec le titre
'The Matrix'et l'année1999, puis définissez uniquement sa note sur8.7(laissez le réalisateur à null) - Créez un film avec le titre
'Upcoming Film'et l'année2025(laissez le réalisateur et la note à null) - Appelez
displayInfo()sur chaque film dans l'ordre listé ci-dessus
- Créez un film avec le titre
La méthode displayInfo() doit imprimer exactement dans ce format :
[title] ([year])
Director: [director or "Unknown"]
Rating: [rating or "Not rated"]Remarquez comment les champs non-nullables (title et year) sont toujours garantis d'avoir des valeurs, tandis que les champs nullables (director? et rating?) peuvent rester non définis. Cela reflète des scénarios du monde réel où certaines données sont essentielles et d'autres facultatives.
Sortie attendue :
Inception (2010)
Director: Christopher Nolan
Rating: 8.8
The Matrix (1999)
Director: Unknown
Rating: 8.7
Upcoming Film (2025)
Director: Unknown
Rating: Not ratedAide-mémoire
Pour rendre un type nullable en Dart, ajoutez un ? après le nom du type :
String name = 'Alice'; // Non-nullable - must always have a value
String? nickname; // Nullable - can be null or a StringCette distinction s'applique à tous les types :
int count = 10; // Must have a value
int? optionalCount; // Can be null
List<String> items = []; // Must be a list (can be empty)
List<String>? maybeItems; // Could be null (no list at all)Une liste vide [] est différente de null. Une liste vide existe mais ne contient rien ; null signifie qu'aucune liste n'existe du tout.
Le compilateur applique strictement les règles de sécurité nulle (null safety). Vous ne pouvez pas assigner null à une variable non-nullable, et vous ne pouvez pas utiliser une variable nullable là où une variable non-nullable est attendue sans avoir préalablement vérifié si elle est nulle :
String? maybeName = 'Bob';
// String definite = maybeName; // Error! Can't assign nullable to non-nullableEssayez vous-même
import 'movie.dart';
void main() {
// TODO: Créer un film avec le titre 'Inception' et l'année 2010
// Ensuite, définir son réalisateur sur 'Christopher Nolan' et sa note sur 8.8
// TODO: Créer un film avec le titre 'The Matrix' et l'année 1999
// Ensuite, définir uniquement sa note sur 8.7 (laisser le réalisateur à null)
// TODO: Créer un film avec le titre 'Upcoming Film' et l'année 2025
// Laisser à la fois le réalisateur et la note à null
// TODO: Appeler displayInfo() sur chaque film dans l'ordre
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Les bases de la POO
Fichiers externesBibliothèques et importsIntroduction à la POOClasses vs ObjetsLe mot-clé thisMéthodesVariables d'instanceBases des constructeursRécapitulatif - Calculatrice simple4Null Safety
Introduction à la Null SafetyNullable vs Non-NullableLes opérateurs ? et !Le mot-clé late et la Null SafetyLes opérateurs Null-AwareLa Null Safety dans les classesRécapitulatif - Système de profil utilisateur7Classes abstraites et Interfaces
Classes abstraitesMéthodes abstraitesInterfaces en DartInterfaces implicitesImplémentation vs ExtensionInterfaces multiplesRécapitulatif - Calculateur de formes10Collections et Génériques
Aperçu des List, Set et MapCollections Type-SafeClasses génériquesMéthodes génériquesContraintes de généricitéIterable & IteratorRécapitulatif - Stockage générique2Les constructeurs en Dart
Constructeur par défautConstructeurs nommésListes d'initialisationConstructeurs constantsConstructeurs factoryConstructeurs de redirectionRécapitulatif - Shape Builder5Encapsulation
Membres publics vs privésLa convention du préfixe _Visibilité au niveau de la bibliothèqueApprofondissement des Getters & SettersMasquage d'informationsRécapitulatif - Dossiers d'étudiants8Mixins
Introduction aux MixinsCréation de MixinsUtilisation de plusieurs MixinsLe mot-clé on dans les MixinsMixin vs HéritageMixin vs InterfaceRécapitulatif - Système Animal11Méthodes spéciales
Redéfinition de toString()Redéfinition de hashCode & ==Interface ComparableMéthode call()Redéfinition de noSuchMethodRécapitulatif - Collection personnalisée14Patrons de conception Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron ObservateurPatron Stratégie3Propriétés de classe
Membres d'instance vs statiquesChamps Final & ConstVariables LateMéthodes et champs statiquesGetters et SettersRécapitulatif - Gestionnaire de compte bancaire6Héritage
Bases de l'héritageLe mot-clé superRedéfinition de méthodeL'annotation @overrideLe mot-clé final pour les classesConstructeurs et héritageRécapitulatif - Hiérarchie des employés9Polymorphisme
Bases du polymorphismePolymorphisme via les interfacesVérification de type à l'exécutionLes opérateurs is & asMot-clé covariantRécapitulatif - Processeur de paiement12POO Asynchrone
Futures & async/awaitBases des StreamsStream ControllersConstructeurs asynchronesL'asynchrone dans les méthodes de classeRécapitulatif - Data Fetcher15Patrons de conception Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode ModèlePatron ÉtatPatron CompositePatron Repository