Introducción a la seguridad de nulos
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy. Lección 23 de 110.
Una de las fuentes más comunes de errores en programación es intentar usar un valor que no existe. En Dart, esta "ausencia de valor" especial se representa mediante null. La característica de seguridad nula de Dart te ayuda a detectar estos errores incluso antes de que tu código se ejecute.
Sin seguridad contra valores nulos, cualquier variable podría ser potencialmente null, lo que provocaría errores en tiempo de ejecución cuando intentas usarla:
// En Dart antiguo (sin null safety)
String name; // ¡Podría ser null!
print(name.length); // Crash si name es nullCon la seguridad frente a valores nulos habilitada (Dart 2.12+), el compilador distingue entre las variables que pueden contener null y aquellas que no. De forma predeterminada, las variables son no anulables: siempre deben contener un valor válido:
String name = 'Alice'; // Debe tener un valor
print(name.length); // Seguro - name nunca es nullEl compilador se negará a compilar código donde una variable no anulable pueda ser null. Esto traslada la detección de errores del tiempo de ejecución al tiempo de compilación, haciendo que tus programas sean más confiables. En las próximas lecciones, aprenderás cómo declarar tipos anulables cuando realmente los necesites, y los operadores que Dart proporciona para trabajar con valores potencialmente nulos de forma segura.
Desafío
FácilConstruyamos un sistema sencillo de tarjetas de contacto que demuestre la importancia de las variables no anulables. Crearás un sistema en el que cada contacto debe tener información válida y garantizada.
Organizarás tu código en dos archivos:
contact.dart: Define una claseContactque represente la información de contacto de una persona. Como estamos trabajando con seguridad frente a valores nulos, cada campo debe tener un valor válido; ¡no se permiten datos faltantes! Tu clase debe tener:- Un
String firstNamepara el nombre del contacto - Un
String lastNamepara el apellido del contacto - Un
String emailpara la dirección de correo electrónico del contacto - Un
int phoneDigitspara la cantidad de dígitos de su número de teléfono - Un constructor que reciba los cuatro valores
- Un getter
fullNameque devuelva el nombre y el apellido combinados, con un espacio entre ellos - Un método
displayCard()que muestre la información del contacto
- Un
main.dart: Importa tu clase de contacto y crea dos contactos para demostrar que todos los campos tienen valores garantizados:- Crea un contacto con el nombre
'Emma', el apellido'Wilson', el correo electrónico'emma@mail.com'y10dígitos telefónicos - Crea un contacto con el nombre
'James', el apellido'Brown', el correo electrónico'james@work.com'y11dígitos telefónicos - Llama a
displayCard()en cada contacto, en el orden indicado arriba
- Crea un contacto con el nombre
El método displayCard() debe mostrar exactamente este formato:
--- Contact Card ---
Name: [fullName]
Email: [email]
Phone digits: [phoneDigits]Observa cómo cada variable debe inicializarse con un valor real: ¡esto es la seguridad frente a valores nulos en acción! El compilador garantiza que, cuando accedas a fullName, email o cualquier otro campo, siempre contendrá datos válidos.
Salida esperada:
--- Contact Card ---
Name: Emma Wilson
Email: emma@mail.com
Phone digits: 10
--- Contact Card ---
Name: James Brown
Email: james@work.com
Phone digits: 11Pruébalo tú mismo
import 'contact.dart';
void main() {
// TODO: Crear el primer contacto con:
// - nombre: 'Emma'
// - apellido: 'Wilson'
// - email: 'emma@mail.com'
// - dígitos del teléfono: 10
// TODO: Crear el segundo contacto con:
// - nombre: 'James'
// - apellido: 'Brown'
// - email: 'james@work.com'
// - dígitos del teléfono: 11
// TODO: Llamar a displayCard() en cada contacto en orden
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de POO
Archivos externosLibrerías e importacionesIntroducción a la POOClases vs. ObjetosLa palabra clave thisMétodosVariables de instanciaConceptos básicos de constructoresResumen - Calculadora sencilla4Seguridad de nulos
Introducción a la seguridad de nulosNulables vs No nulablesLos operadores ? y !Palabra clave Late y Null SafetyOperadores Null-awareNull Safety en clasesResumen - Sistema de perfil de usuario7Clases abstractas e interfaces
Clases abstractasMétodos abstractosInterfaces en DartInterfaces implícitasImplementar vs. ExtenderInterfaces múltiplesRepaso - Calculadora de figuras10Colecciones y Genéricos
Visión general de List, Set y MapColecciones con seguridad de tiposClases genéricasMétodos genéricosRestricciones genéricasIterable e IteratorResumen - Almacenamiento genérico2Constructores en Dart
Constructor por defectoConstructores nombradosListas de inicializaciónConstructores constantesConstructores de fábricaConstructores de redireccionamientoResumen - Constructor de formas5Encapsulamiento
Miembros públicos vs. privadosLa convención del prefijo _Privacidad a nivel de libreríaProfundidad en Getters y SettersOcultamiento de informaciónResumen - Registros de estudiantes8Mixins
Introducción a los MixinsCreación de MixinsUso de múltiples MixinsPalabra clave on en MixinsMixin vs HerenciaMixin vs InterfazResumen - Sistema Animal11Métodos especiales
Sobrescritura de toString()Sobrescritura de hashCode y ==Interfaz ComparableMétodo call()Sobrescritura de noSuchMethodResumen - Colección personalizada14Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy3Propiedades de clase
Miembros de instancia vs. estáticosCampos Final y ConstVariables LateMétodos y campos estáticosGetters y SettersResumen - Gestor de cuentas bancarias6Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosLa anotación @overrideLa palabra clave final en clasesConstructores y herenciaResumen - Jerarquía de empleados9Polimorfismo
Fundamentos del polimorfismoPolimorfismo mediante interfacesComprobación de tipos en tiempo de ejecuciónLos operadores is y asPalabra clave covariantResumen - Procesador de pagos12POO Asíncrona
Futures y async/awaitFundamentos de StreamsStream ControllersConstructores asíncronosAsincronía en métodos de claseRepaso - Data Fetcher15Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón RepositoryPractica por tu cuenta: Compilador de Dart online