El tipo enumerado es una clase especial que sirve para representar un conjunto de valores constantes con cantidad fija.
Todas las enumeraciones heredan automáticamente de la clase Enum. Al mismo tiempo, las enumeraciones son tipos sellados (sealed): no se pueden heredar, implementar, mezclar ni instanciar explícitamente de forma manual.
Las clases abstractas y los mixins pueden implementar o heredar explícitamente Enum, pero no es posible crear objetos reales de esa clase o mixin a menos que una enumeración declare su implementación o mezcla.
Usa la palabra clave enum y lista todas las constantes de enumeración para definir una enumeración simple:
enum Color { red, green, blue }
Se permite añadir una coma al final al declarar una enumeración, lo que facilita copiar y pegar y reduce errores en el código.
Enumeraciones mejoradas (Enhanced enums)
Dart admite enumeraciones mejoradas. Al igual que en las clases normales, puedes definir campos miembros, métodos y constructores constantes, pero sus instancias solo pueden ser las constantes fijas definidas previamente.
Declarar una enumeración mejorada requiere cumplir una serie de restricciones obligatorias:
- Las variables de instancia deben ser
final(incluyendo variables introducidas por mixins) - Todos los constructores generativos deben llevar la etiqueta
const - Los constructores de fábrica solo pueden devolver instancias constantes definidas dentro de la enumeración
- No se puede heredar explícitamente otra clase (la herencia de
Enumse realiza automáticamente) - No se pueden sobrescribir
index,hashCodeni el operador de igualdad== - No se puede definir un miembro llamado
valuesdentro de la enumeración, ya que entraría en conflicto con el accesor estáticovaluesgenerado automáticamente - Todas las instancias de la enumeración deben escribirse al principio de su definición y se requiere al menos una instancia
- Dentro de los métodos de instancia de una enumeración mejorada, puedes usar
thispara hacer referencia a la constante de enumeración actual
Ejemplo
enum Vehicle implements Comparable<Vehicle> {
car(tires: 4, passengers: 5, carbonPerKilometer: 400),
bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);
const Vehicle({
required this.tires,
required this.passengers,
required this.carbonPerKilometer,
});
final int tires;
final int passengers;
final int carbonPerKilometer;
// Getter
int get carbonFootprint => (carbonPerKilometer / passengers).round();
bool get isTwoWheeled => this == Vehicle.bicycle;
@override
int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}
A partir de Dart 3.13, los constructores principales simplifican la sintaxis de las enumeraciones mejoradas:
enum Vehicle(
final int tires,
final int passengers,
final int carbonPerKilometer,
) implements Comparable<Vehicle> {
car(4, 5, 400),
bus(6, 50, 800),
bicycle(2, 1, 0);
int get carbonFootprint => (carbonPerKilometer / passengers).round();
bool get isTwoWheeled => this == Vehicle.bicycle;
@override
int compareTo(Vehicle other) => carbonFootprint - other.carbonFootprint;
}
Uso de enumeraciones
Se accede a las constantes de enumeración igual que a las variables estáticas:
final favoriteColor = Color.blue;
if (favoriteColor == Color.blue) {
print('¡Tu color favorito es el azul!');
}
Propiedad index
Cada constante de enumeración cuenta con la propiedad index, que devuelve el número de orden que empieza desde 0 dentro de la definición:
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
Constante estática values
Obtén la lista con todos los valores de la enumeración mediante NombreEnumeracion.values:
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);
Combinar enumeraciones con switch
Al usar una enumeración en un switch, el compilador mostrará una advertencia si no cubres todas las ramas. Puedes usar default para cubrir los casos restantes.
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('Rojo como las rosas!');
case Color.green:
print('Verde como el pasto!');
default:
print(aColor); // Color.blue
}
Propiedad name
Obtén el nombre de texto correspondiente a la constante mediante .name:
print(Color.blue.name); // Muestra "blue"
Acceder a miembros personalizados de la enumeración
En las enumeraciones mejoradas puedes acceder a campos, getters y métodos personalizados como en cualquier objeto normal:
print(Vehicle.car.carbonFootprint);
A continuación tienes un ejemplo completo de esta lección: crearemos una enumeración para los meses y pondremos en práctica todos los conocimientos aprendidos.
enum Month implements Comparable<Month> {
january(1, '一月', days: 31),
february(2, '二月', days: 28),
march(3, '三月', days: 31),
april(4, '四月', days: 30),
may(5, '五月', days: 31),
june(6, '六月', days: 30),
july(7, '七月', days: 31),
august(8, '八月', days: 31),
september(9, '九月', days: 30),
october(10, '十月', days: 31),
november(11, '十一月', days: 30),
december(12, '十二月', days: 31);
const Month(this.monthNumber, this.cnName, {required this.days});
/// Número de mes gregoriano, del 1 al 12
final int monthNumber;
/// Nombre
final String cnName;
/// Días en año común
final int days;
/// Getter: ¿Pertenece al primer trimestre?
bool get isFirstQuarter => monthNumber <= 3;
/// Getter: ¿Tiene 31 días?
bool get has31Days => days == 31;
/// Método personalizado: comprobar si febrero corresponde a año bisiesto
bool isLeapYearFebruary(int year) {
if (this != Month.february) return false;
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
/// Implementa Comparable para permitir ordenación
@override
int compareTo(Month other) {
return monthNumber - other.monthNumber;
}
}
void main() {
// 1. Acceso básico a constantes de enumeración
Month current = Month.august;
print('Enumeración actual: $current');
print('Propiedad name de la enumeración: ${current.name}');
print('Mes: ${current.cnName}');
print('Número de mes 1~12: ${current.monthNumber}');
print('Días en año común: ${current.days}');
print('¿Mes de 31 días? ${current.has31Days}');
print('¿Pertenece al primer trimestre? ${current.isFirstQuarter}');
// 2. Propiedad index (índice de definición, empieza en 0)
print('\n${Month.january.name} index = ${Month.january.index}');
print('${Month.december.name} index = ${Month.december.index}');
// 3. values para obtener lista completa de meses
List<Month> allMonths = Month.values;
print('\nHay un total de ${allMonths.length} meses');
// 4. Usar switch con enumeración
print('\n==== Prueba switch ====');
switch (current) {
case Month.january:
print('Inicio del año');
case Month.february:
print('Puede tener día bisiesto');
case Month.march:
case Month.april:
case Month.may:
print('Primavera');
case Month.june:
case Month.july:
case Month.august:
print('Verano');
case Month.september:
case Month.october:
case Month.november:
print('Otoño');
case Month.december:
print('Invierno, fin de año');
}
// 5. Llamada al método personalizado
Month feb = Month.february;
print('\n¿Febrero 2024 es mes bisiesto? ${feb.isLeapYearFebruary(2024)}');
print('¿Febrero 2025 es mes bisiesto? ${feb.isLeapYearFebruary(2025)}');
// 6. Ordenar enumeraciones (mediante interfaz Comparable)
var selected = [Month.october, Month.january, Month.july];
selected.sort();
print('\nMeses ordenados: ${selected.map((m) => m.cnName).toList()}');
}
Resultado de ejecución
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Enumeración actual: Month.august
Propiedad name de la enumeración: august
Mes: 八月
Número de mes 1~12: 8
Días en año común: 31
¿Mes de 31 días? true
¿Pertenece al primer trimestre? false
january index = 0
december index = 11
Hay un total de 12 meses
==== Prueba switch ====
Verano
¿Febrero 2024 es mes bisiesto? true
¿Febrero 2025 es mes bisiesto? false
Meses ordenados: [一月, 七月, 十月]
Enumeraciones