Los operadores ? y !
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 25 de 110.
Al trabajar con tipos que admiten valores nulos, Dart proporciona dos operadores esenciales para acceder a los valores de forma segura. El operador de acceso null-aware ?. y el operador de aserción nula ! te brindan control sobre cómo manejas los valores potencialmente nulos.
El operador ?. accede de forma segura a propiedades o métodos en un valor que admite nulos. Si el valor es null, toda la expresión devuelve null en lugar de fallar:
String? name = 'Alice';
print(name?.length); // 5
name = null;
print(name?.length); // null (¡sin errores!)El operador ! le dice a Dart "estoy seguro de que este valor no es nulo". Convierte un tipo nullable a non-nullable, pero lanza un error si el valor es realmente nulo:
String? maybeName = 'Bob';
String definite = maybeName!; // OK - afirmamos que no es nulo
print(definite.length); // 3
String? empty = null;
// String crash = empty!; // ¡Error en tiempo de ejecución! El valor era nuloUsa ?. cuando quieras manejar valores nulos de forma elegante. Usa ! solo cuando estés absolutamente seguro de que existe un valor, quizás después de comprobarlo con una sentencia if o cuando sepas que la lógica garantiza un valor. El uso excesivo de ! anula el propósito de la seguridad contra nulos y puede provocar fallos en tiempo de ejecución.
Desafío
FácilVamos a construir un sistema de inventario de productos que demuestre cómo trabajar de forma segura con valores nulos utilizando los operadores ?. y !.
Crearás dos archivos para organizar tu código:
product.dart: Define una claseProductque represente un artículo en el inventario. Algunos productos tienen información completa, mientras que otros aún se están catalogando. Tu clase debe tener:- Un
String nameno nulo: cada producto debe tener un nombre - Un
double priceno nulo: cada producto debe tener un precio - Un
String? descriptionnulo: algunos productos aún no tienen descripción - Un
String? categorynulo: algunos productos no han sido categorizados - Un constructor que tome
nameypricecomo parámetros requeridos - Un método
getDescriptionLength()que devuelva la longitud de la descripción usando?., onullsi no hay descripción - Un método
getCategoryUppercase()que devuelva la categoría en mayúsculas usando!; este método asume que la categoría ha sido establecida - Un método
displayProduct()que imprima la información del producto, mostrando"No description"cuando la descripción sea nula y"Uncategorized"cuando la categoría sea nula
- Un
main.dart: Importa tu clase de producto y demuestra ambos operadores:- Crea un producto llamado
'Laptop'con un precio de999.99, luego establece su descripción como'High-performance computing device'y su categoría como'Electronics' - Crea un producto llamado
'Mystery Item'con un precio de49.99(deja la descripción y la categoría como nulas) - Para la Laptop: llama a
displayProduct(), imprime'Description length: [length]'usandogetDescriptionLength(), e imprime'Category: [uppercase]'usandogetCategoryUppercase() - Para el Mystery Item: llama a
displayProduct()e imprime'Description length: [length]'usandogetDescriptionLength()(esto mostraránull)
- Crea un producto llamado
El método displayProduct() debe imprimir en este formato:
Product: [name] - $[price]
Description: [description or "No description"]
Category: [category or "Uncategorized"]Salida esperada:
Product: Laptop - $999.99
Description: High-performance computing device
Category: Electronics
Description length: 32
Category: ELECTRONICS
Product: Mystery Item - $49.99
Description: No description
Category: Uncategorized
Description length: nullPruébalo tú mismo
import 'product.dart';
void main() {
// TODO: Crea un producto llamado 'Laptop' con el precio 999.99
// Luego establece su descripción como 'High-performance computing device'
// Y establece su categoría como 'Electronics'
// TODO: Crea un producto llamado 'Mystery Item' con el precio 49.99
// Deja la descripción y la categoría como null
// TODO: Para la Laptop:
// - Llama a displayProduct()
// - Imprime "Description length: [length]" usando getDescriptionLength()
// - Imprime "Category: [uppercase]" usando getCategoryUppercase()
// TODO: Para el Mystery Item:
// - Llama a displayProduct()
// - Imprime "Description length: [length]" usando getDescriptionLength()
}
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 Repository