Anulável vs. não anulável
Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy. Lição 24 de 110.
Agora que você entende por que a null safety é importante, vamos ver como declarar variáveis que podem conter null. No Dart, você torna um tipo anulável adicionando um ? após o nome do tipo.
String name = 'Alice'; // Não anulável - deve sempre ter um valor
String? nickname; // Anulável - pode ser nulo ou uma String
print(name); // Alice
print(nickname); // nullA principal diferença é que os tipos não anuláveis garantem que um valor existe, enquanto os tipos anuláveis permitem explicitamente a ausência de um valor. Essa distinção se aplica a todos os tipos:
int count = 10; // Deve ter um valor
int? optionalCount; // Pode ser nulo
List<String> items = []; // Deve ser uma lista (pode estar vazia)
List<String>? maybeItems; // Pode ser nulo (nenhuma lista)Observe que uma lista vazia [] é diferente de null. Uma lista vazia existe, mas não contém nada; null significa que nenhuma lista existe.
O compilador impõe essas regras estritamente. Você não pode atribuir null a uma variável não anulável, e você não pode usar uma variável anulável onde uma não anulável é esperada sem primeiro verificar se há nulo:
String? maybeName = 'Bob';
// String definite = maybeName; // Erro! Não é possível atribuir um valor anulável a um não anulávelNa próxima lição, você aprenderá os operadores que o Dart oferece para trabalhar com segurança com valores anuláveis.
Desafio
FácilVamos criar um sistema de lista de filmes para assistir que demonstre a diferença entre informações obrigatórias e opcionais usando tipos anuláveis e não anuláveis.
Você criará dois arquivos para organizar seu código:
movie.dart: Defina uma classeMovieque represente um filme na sua lista de filmes para assistir. Todo filme deve ter um título e um ano de lançamento (eles são sempre obrigatórios), mas alguns detalhes adicionais podem não estar disponíveis para todos os filmes. Sua classe deve ter:- Uma
String titlenão anulável — todo filme deve ter um título - Um
int yearnão anulável — todo filme deve ter um ano de lançamento - Uma
String? directoranulável — o diretor pode ser desconhecido - Um
double? ratinganulável — nem todos os filmes foram avaliados ainda - Um construtor que receba
titleeyearcomo parâmetros obrigatórios - Um método
displayInfo()que exiba as informações do filme, mostrandoUnknownquando o diretor estiver ausente eNot ratedquando a avaliação estiver ausente
- Uma
main.dart: Importe sua classe de filme e crie uma pequena lista de filmes para assistir demonstrando dados completos e incompletos:- Crie um filme com o título
'Inception'e o ano2010, depois defina seu diretor como'Christopher Nolan'e sua avaliação como8.8 - Crie um filme com o título
'The Matrix'e o ano1999, depois defina apenas sua avaliação como8.7(deixe o diretor como null) - Crie um filme com o título
'Upcoming Film'e o ano2025(deixe o diretor e a avaliação como null) - Chame
displayInfo()em cada filme na ordem listada acima
- Crie um filme com o título
O método displayInfo() deve exibir exatamente neste formato:
[title] ([year])
Director: [director or "Unknown"]
Rating: [rating or "Not rated"]Observe como os campos não anuláveis (title e year) têm valores sempre garantidos, enquanto os campos anuláveis (director? e rating?) podem permanecer sem definição. Isso reflete situações do mundo real em que alguns dados são essenciais e outros são opcionais.
Saída esperada:
Inception (2010)
Director: Christopher Nolan
Rating: 8.8
The Matrix (1999)
Director: Unknown
Rating: 8.7
Upcoming Film (2025)
Director: Unknown
Rating: Not ratedExperimente você mesmo
import 'movie.dart';
void main() {
// TODO: Criar um filme com o título 'Inception' e ano 2010
// Depois definir seu diretor como 'Christopher Nolan' e a nota como 8.8
// TODO: Criar um filme com o título 'The Matrix' e ano 1999
// Depois definir apenas sua nota como 8.7 (deixar o diretor como nulo)
// TODO: Criar um filme com o título 'Upcoming Film' e ano 2025
// Deixar tanto o diretor quanto a nota como nulos
// TODO: Chamar displayInfo() em cada filme na ordem
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP
Arquivos externosBibliotecas e importsIntrodução à OOPClasses vs. objetosA palavra-chave thisMétodosVariáveis de instânciaNoções básicas de construtoresRevisão - Calculadora simples4Segurança contra nulos
Introdução à segurança contra nulosAnulável vs. não anulávelOs operadores ? e !Palavra-chave Late e segurança contra nulosOperadores conscientes de nulosSegurança contra nulos em classesRecapitulação — Sistema de perfil de usuário7Classes Abstratas e Interfaces
Classes AbstratasMétodos AbstratosInterfaces em DartInterfaces ImplícitasImplementação vs. ExtensãoMúltiplas InterfacesRecapitulação - Calculadora de Formas10Coleções e Genéricos
Visão geral de List, Set e MapColeções com segurança de tiposClasses genéricasMétodos genéricosRestrições genéricasIterable e IteratorRecapitulação - Armazenamento genérico13Conceitos Avançados de OOP
Composição vs. HerançaMétodos de ExtensãoClasses ChamáveisClasses Seladas (Dart 3)Registros (Dart 3)Padrões e Correspondência (3.0)Enums com Métodos16Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses de Livros e Usuários2Construtores em Dart
Construtor padrãoConstrutores nomeadosListas de inicializaçãoConstrutores constantesConstrutores factoryConstrutores de redirecionamentoRevisão - Construtor de formas5Encapsulamento
Membros Públicos vs. PrivadosConvenção do Prefixo _Privacidade no Nível da BibliotecaAprofundamento em Getters e SettersOcultação de InformaçõesRecapitulação - Registros de Alunos8Mixins
Introdução a MixinsCriando MixinsUsando vários MixinsPalavra-chave on em MixinsMixin vs HerançaMixin vs InterfaceRecapitulação - Sistema de Animais11Métodos Especiais
Sobrescrita de toString()Sobrescrita de hashCode e ==Interface ComparableMétodo call()Sobrescrita de noSuchMethodRecapitulação - Coleção Personalizada14Padrões de Projeto – Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy3Propriedades de Classe
Membros de Instância vs. EstáticosCampos Final e ConstVariáveis LateMétodos e Campos EstáticosGetters e SettersRecapitulação - Gerenciador de Contas Bancárias6Herança
Herança BásicaA Palavra-chave superSobrescrita de MétodosA Anotação @overrideA Palavra-chave final para ClassesConstrutores e HerançaRecapitulação - Hierarquia de Funcionários9Polimorfismo
Fundamentos do polimorfismoPolimorfismo por meio de interfacesVerificação de tipos em tempo de execuçãoOs operadores is e asPalavra-chave covarianteRecapitulação — Processador de pagamentos12OOP Assíncrona
Futures e async/awaitNoções básicas de StreamsControladores de StreamConstrutores assíncronosAsync em métodos de classeRecapitulação — Buscador de dados15Padrões de Projeto — Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão RepositoryPratique por conta própria: Compilador de Dart online