Seguridad Null
## Objetivos de Aprendizaje
- Comprender la seguridad null en Dart
- Dominar tipos anulables
- Usar operadores nulos
- Trabajar con variables late
## Por Que Seguridad Null?
### El Problema
```dart
// Sin seguridad null
String? name; // Puede ser null
print(name.length); // Error en tiempo de ejecucion si es null!
```
### La Solucion de Dart
```dart
// Con seguridad null - detectado en tiempo de compilacion
String name = 'Alice'; // No puede ser null
// name = null; // Error!
String? optional; // Anulable
optional = null; // OK
// print(optional.length); // Error! No se puede acceder sin verificacion null
```
## Tipos Anulables
### Sintaxis Basica
```dart
void main() {
// No anulable (debe tener valor)
String name = 'Alice';
// Anulable (puede ser null)
String? nullable;
nullable = null; // OK
nullable = 'Bob'; // OK
}
```
### Se Requiere Verificacion Null
```dart
void main() {
String? nullable;
// Error: nullable no puede asignarse a no anulable
// String mustNotBeNull = nullable;
// Solucion 1: Verificar si es null
if (nullable != null) {
String definitelyNotNull = nullable; // OK
print(definitelyNotNull.length);
}
// Solucion 2: Usar operadores para anulables directamente
print(nullable?.length); // null (acceso seguro)
}
```
## Operadores Nulos
### Acceso Nulo (?)
```dart
void main() {
String? name;
print(name?.length); // null (no lanza excepcion)
name = 'Alice';
print(name?.length); // 5
}
```
### Asignacion Nula (??=)
```dart
void main() {
String? name;
name ??= 'Por Defecto'; // Solo asigna si es null
print(name); // Por Defecto
name = 'Alice';
name ??= 'Por Defecto'; // Sin efecto ya que no es null
print(name); // Alice
}
```
### Indice Nulo ([]?)
```dart
void main() {
List? numbers = [1, 2, 3];
print(numbers?[0]); // 1
numbers = null;
print(numbers?[0]); // null
}
```
### Operador If-null (??)
```dart
void main() {
String? name;
// Devuelve izquierda si no es null, si no derecha
String displayName = name ?? 'Invitado';
print(displayName); // Invitado
name = 'Alice';
displayName = name ?? 'Invitado';
print(displayName); // Alice
}
```
### Invocacion de Metodo Nula
```dart
void main() {
String? text;
// Solo invoca si no es null
text?.toUpperCase(); // null
text = 'hola';
text?.toUpperCase(); // HOLA
}
```
## Desenvoltura Forzada (!)
### Cuando Usar
```dart
void main() {
String? name = 'Alice';
// Usar ! cuando estas seguro de que no es null
// Solo usar si has verificado o sabes que esta garantizado
print(name!.length); // 5
// Peligro!
String? danger;
// print(danger!.length); // Error en tiempo de ejecucion!
}
```
### Patron para Non-null Conocido
```dart
void main() {
String? compute() {
// ... logica compleja que siempre devuelve no null
return 'resultado';
}
String result = compute()!; // Seguro si confias en la logica
print(result.length);
}
```
## Variables Late
### Uso Basico
```dart
late String description;
void init() {
description = 'Inicializado';
}
void main() {
// print(description); // Error si se accede antes de init()
init();
print(description); // Inicializado
}
```
### Con Final
```dart
late final String config;
void load() {
config = 'Cargado';
}
void main() {
load();
print(config); // Cargado
}
```
### Inicializacion Perezosa
```dart
late String expensive = compute();
String compute() {
print('Calculando...');
return 'Resultado';
}
void main() {
// expensive aun no se ha calculado
print('Antes del acceso');
print(expensive); // Calculando... Resultado
}
```
### Casos de Uso
```dart
class User {
late String displayName;
User(Map data) {
// Operacion costosa diferida
displayName = data['name'] ?? 'Desconocido';
}
}
```
## Seguridad Null en Funciones
### Parametros
```dart
// Parametro anulable
void greet(String? name) {
if (name != null) {
print('Hola, $name');
}
}
// No anulable requerido
void greetRequired(String name) {
print('Hola, $name');
}
void main() {
greet(null); // OK
greet('Alice'); // OK
// greetRequired(null); // Error!
greetRequired('Alice'); // OK
}
```
### Tipos de Retorno
```dart
// Retorno anulable
String? findName() {
return 'Alice';
// o return null;
}
// Retorno no anulable (siempre debe devolver valor)
String findGreeting() {
return 'Hola';
}
```
## Seguridad Null en Clases
### Campos Anulables
```dart
class User {
String name;
String? email; // Anulable
User(this.name, [this.email]);
}
void main() {
var user = User('Alice', 'alice@email.com');
print(user.email); // alice@email.com
var user2 = User('Bob');
print(user2.email); // null
}
```
### Campos Late
```dart
class DataService {
late String data;
Future load() async {
data = await fetchData();
}
}
```
### Campos Anulables con Late
```dart
class Config {
late String? cachedData;
void load() {
cachedData = fetch();
}
String? get() {
return cachedData;
}
}
```
## Seguridad Null en Colecciones
### Elementos Anulables
```dart
void main() {
// Lista de cadenas anulables
List items = ['a', null, 'b', null, 'c'];
for (var item in items) {
if (item != null) {
print(item.toUpperCase());
}
}
}
```
### Coleccion Anulable
```dart
void main() {
// Lista anulable
List? nullableList;
print(nullableList?.length); // null
nullableList = [1, 2, 3];
print(nullableList?.length); // 3
}
```
## Seguridad Null en Genericos
### Argumentos de Tipo Anulables
```dart
void main() {
// List - lista de cadenas anulables
List nullableStrings = ['a', null, 'b'];
// List? - lista anulable de cadenas
List? optionalList;
// Map - claves y valores anulables
Map mixed = {null: 0, 'a': 1};
}
```
## No Anulable por Defecto en Dart 3
### Parametros Nombrados Requeridos
```dart
void createUser({
required String name,
String? email, // Opcional
int age = 0,
}) {
print('$name, $email, $age');
}
void main() {
createUser(name: 'Alice'); // OK
// createUser(); // Error: name es requerido
}
```
## Mejores Practicas
### 1. Preferir Tipos No Anulables
```dart
// Mal
String? name = 'Alice';
// Bien
String name = 'Alice';
```
### 2. Usar Late con Moderacion
```dart
// Solo cuando es necesario
late String data;
// Mejor si puedes usar el constructor
Data(this.data); // preferido
```
### 3. Usar Verificaciones Null
```dart
// Antes de acceder a anulable
if (value != null) {
value.someMethod();
}
// O usar operadores seguros
value?.someMethod();
```
### 4. Proporcionar Valores por Defecto
```dart
// Con operador ??
String display = name ?? 'Desconocido';
// Con ??= para mutables
name ??= 'Por Defecto';
```
## Resumen
- Dart es seguro para null por defecto
- Sufijo `?` hace el tipo anulable
- `?.` acceso seguro a propiedades
- `??` operador if-null
- `??=` asignacion nula
- `!` desenvolvimiento forzado (usar con cuidado)
- `late` difiere la inicializacion
- La seguridad null previene errores de null en tiempo de ejecucion en tiempo de compilacion
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →