DMarlon Studio

Lección 8 · 8 de 20

Enums mejorados · Dart

Dé campos, constructor y métodos a sus enums en Dart y modele con ellos el ciclo de vida de un pedido, con un switch que el compilador comprueba.

Dart · Enums mejorados en DMarlon Studio: el código del ejemplo y su salida en la terminal

Un enum de Dart puede ser mucho más que una lista de nombres: los enums mejorados tienen campos, constructor y métodos. OrderStatus enumera los estados de un pedido, y cada valor lleva su etiqueta (label) y si todavía se puede cancelar (canCancel).

Los valores se escriben arriba, cada uno con sus argumentos, y la lista termina en punto y coma. El constructor tiene que ser `const` y los campos final, porque cada valor es una constante que se crea una sola vez. canCancel es un parámetro con nombre que vale false por defecto, así que solo pending y paid tienen que indicarlo.

El getter next usa una expresión `switch` sobre this para dar el estado siguiente. No lleva un caso _ final: el compilador conoce todos los valores del enum y comprueba que estén cubiertos (delivered || cancelled agrupa dos en un caso). Si mañana se añade un estado, el switch deja de compilar hasta que se trate. isFinal se apoya en next.

En main, el bucle recorre el flujo del pedido hasta que next da null. Todo enum trae además values (la lista de valores), name (su nombre como texto), index (su posición) y values.byName, que convierte un texto en el valor correspondiente: muy útil al leer un estado guardado en JSON o en una base de datos.

Código · main.dart

// An enhanced enum: each value carries data and the enum has methods.enum OrderStatus {  pending('Pending', canCancel: true),  paid('Paid', canCancel: true),  shipped('Shipped'),  delivered('Delivered'),  cancelled('Cancelled');  const OrderStatus(this.label, {this.canCancel = false});  final String label;  final bool canCancel;  OrderStatus? get next => switch (this) {        pending => paid,        paid => shipped,        shipped => delivered,        delivered || cancelled => null,      };  bool get isFinal => next == null;}void main() {  OrderStatus? status = OrderStatus.pending;  while (status != null) {    final flags = '${status.canCancel ? 'can cancel' : 'locked'}, final: ${status.isFinal}';    print('${status.label.padRight(9)} -> $flags');    status = status.next;  }  print(OrderStatus.values.map((s) => s.name).join(' | '));  final shipped = OrderStatus.values.byName('shipped');  print('${shipped.label} is value number ${shipped.index}');}

Salida · dart run main.dart

Pending   -> can cancel, final: false
Paid      -> can cancel, final: false
Shipped   -> locked, final: false
Delivered -> locked, final: true
pending | paid | shipped | delivered | cancelled
Shipped is value number 2

Para recordar

  • Un enum mejorado tiene campos, un constructor const y métodos.
  • Cada valor se declara con sus argumentos.
  • Un switch sobre un enum debe cubrir todos sus valores.
  • values, name, index y byName vienen incluidos.
  • Un estado nuevo obliga a revisar cada switch, y eso evita olvidos.

Ejercicio

Añada un estado returned('Returned') y haga que siga a delivered; el compilador le obligará a tratarlo en el switch de next.