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 anulables, Dart proporciona dos operadores esenciales para acceder a los valores de forma segura. El operador de acceso consciente de valores nulos ?. y el operador de aserción de no nulidad ! te permiten controlar cómo gestionas los valores que podrían ser 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 indica a Dart: «Estoy seguro de que este valor no es nulo». Convierte un tipo anulable en uno no anulable, pero produce un error si el valor realmente es 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ácilConstruyamos un sistema de inventario de productos que demuestre cómo trabajar de forma segura con valores anulables usando los operadores ?. y !.
Crearás dos archivos para organizar tu código:
product.dart: Define una claseProductque represente un artículo del inventario. Algunos productos tienen información completa, mientras que otros todavía se están catalogando. Tu clase debe tener:- Un
String nameno anulable: todo producto debe tener un nombre - Un
double priceno anulable: todo producto debe tener un precio - Un
String? descriptionanulable: algunos productos todavía no tienen descripción - Un
String? categoryanulable: algunos productos todavía no han sido categorizados - Un constructor que reciba
nameypricecomo parámetros obligatorios - 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 supone que la categoría ha sido establecida - Un método
displayProduct()que muestre la información del producto, mostrandoNo descriptioncuando la descripción sea nula yUncategorizedcuando la categoría sea nula
- Un
main.dart: Importa tu clase de producto y demuestra ambos operadores:- Crea un producto llamado
'Laptop'con el precio999.99, después establece su descripción como'High-performance computing device'y su categoría como'Electronics' - Crea un producto llamado
'Mystery Item'con el precio49.99(deja la descripción y la categoría como nulas) - Para Laptop: llama a
displayProduct(), muestraDescription length: [length]usandogetDescriptionLength()y muestraCategory: [uppercase]usandogetCategoryUppercase() - Para Mystery Item: llama a
displayProduct()y muestraDescription length: [length]usandogetDescriptionLength()(esto mostraránull)
- Crea un producto llamado
El método displayProduct() debe mostrar el siguiente 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 RepositoryPractica por tu cuenta: Compilador de Dart online