Basic usage
Enumerated types are very common data type in programming languages. It's used to represent a fixed number of constant values. In dart, you can declare a enumerated type with the enum keyword.
enum Pet { cat, dog, fish }
void main() {
  final values = Pet.values;
  print(values); // [Pet.cat, Pet.dog, Pet.fish]
  print(Pet.cat); // Pet.cat
  print(Pet.dog.index); // 1
  print(Pet.fish == values[2]); // true
}
All enums implicitly extend the Enum class, the desugaring version of code above is:
class Pet extends Enum {  
  static const Pet cat = Pet._$(0, "cat");  
  static const Pet dog = Pet._$(1, "dog");  
  static const Pet fish = Pet._$(2, "fish");  
  static const List<Pet> values = [cat, dog, fish];  
  const Pet._$(int _$index, String _$name) : super._(_$index, _$name);  
  String _$enumToString() => "Pet.${_$name}";
}
abstract class Enum {
  Enum._(this.index, this._name);  
  final int index;
  final String _name;
  String _$enumToString();
  String toString() => _$enumToString();
}
The enum types are designed to be primitive equality, so enums can be used in switch statement.
void main() {
  final pet = Pet.fish;
  switch (pet) {
    case Pet.cat:
      print('Cat');
      break;
    case Pet.dog:
      print('Dog');
      break;
    default:
      print("Fish");
  }
}
The enum types are completely sealed by default. Being sealed means they cannot be subclassed, implemented, mixed in, or otherwise explicitly instantiated.
class FurryPet extends Pet {} 
// Error: 'Pet' is an enum and can't be extended or implemented.
class PocketPet implements Pet {} 
// Error: 'Pet' is an enum and can't be extended or implemented.
mixin PetMixin on Pet {} 
// Error: 'Pet' is an enum and can't be extended or implemented.
const bird = Pet(3, 'Bird'); 
// Error: Enums can't be instantiated.
Quite simple, right? But what if we wanna get the name of a enum value, or get value by name. We need to do something like below
void main() {
  print(Pet.cat.toString().split('.').last); // cat
  // names in non-english
  const names = ['chat', 'chien', 'poisson']; 
  print(names[Pet.fish.index]); // poisson
  // find enum value by name
  final dog = Pet.values.firstWhere((e) => e.toString().split('.').last == 'dog');
  print(dog); // Pet.dog
}
Enum extension
Since dart 2.6,  we can add custom methods to enum with extension methods.
enum Color {
  red,
  green,
  blue,
}
extension ColorExt on Color {
  // names in non-english
  String get name {
    switch (this) {
      case Color.red:
        return 'rojo';
      case Color.green:
        return 'verde';
      default:
        return 'azul';
    }
  }
  String get hexCode {
    const hexCodes = ['#FF0000', '#00FF00', '#0000FF'];
    return hexCodes[this.index];
  }
}
void main() {
  print(Color.green.name); // verde
  print(Color.blue.hexCode); // #0000FF
}
As getting the name of a enum value as String is quite often needed, dart 2.15 introduced an official EnumExtension to do the very same thing.
void main() {
  // dart < 2.15
  print(Color.red.toString().split('.').last) // red
  // dart >= 2.15, with official EnumExtension
  print(Color.red.name); // red
}
Enhanced enum
Dart 2.17 shipped with the enhanced enum, which makes enum behaves more like a class. Enhanced enum supports generic and can be declared with fields(static or instance member), methods or implements interfaces and applies mixins.
// enhanced enum syntax
enum Name<T extends Object?> with Mixin1, Mixin2 implements Interface1, Interface2 {
  id1<int>(args1), id2<String>(args2), id3<bool>(args3);
  memberDeclaration*
  const Name(params) : initList;
}
Let's rewrite our previous extension method version Color enum into a enhanced one.
enum Color {
  red('#FF0000', 'Red'),
  green('#00FF00', 'Green'),
  blue('#0000FF', 'Blue');
  const Color(this.hexCode, this.name);
  final String hexCode;
  final String name;
  @override
  String toString() => '$name: $hexCode';
}
void main() {
  final blue = Color.blue;
  print(blue.hexCode); // #00FF00
  print(blue.name); // Blue
  print(blue); // Blue: #00FF00
}
Thanks to this feature the code becomes much more clear to read and easy to maintain.
Let's write a more complex one
mixin Pet {
  keepCompany() => print('keep you company');
}
enum Dog with Pet implements Comparable<Dog> {
  akita.guardDog('Akita', 'japan'), // generate instance with named constructor
  bulldog('Bulldog', 'england', false),
  chihuahua('Chihuahua', 'mexico', false);
  final bool guardDog;
  final String name;
  final String originCountry;
  // generative constructor can only called in the enum 
  const Dog(this.name, this.originCountry, this.guardDog);
  // named constructor with initializers
  const Dog.guardDog(String name, String country)
      : this.name = name,
        this.originCountry = country,
        this.guardDog = true;
  // factory constructor can only return one of the known values
  // redirect to generative constructor is illegal
  factory Dog.japanDog() {
    return values.firstWhere((value) => value.originCountry == 'japan');
  }
  // implements the Comparable interface to make it sortable
  int compareTo(Dog another) => this.index - another.index;
  // override the default toString method
  String toString() => name;
}
void main() {
  List<Dog> dogs = [Dog.bulldog, Dog.chihuahua, Dog.akita];
  dogs.sort((a, b) => a.compareTo(b));
  print(dogs);
  print(Dog.chihuahua.keepCompany());
}
As enum is used for fixed number of constant values,  there are some restrictions applied to enhanced enum.
- Enhanced enum can not extend class other than the 
Enumclass. - All generative constructors (constructors that generate instance of class) must be constant. this ensures all enum instances are constant value .
 - Factory constructors can only return one of the fixed, known enum instances.
 - All instances must be declared in the beginning of the enum declaration, and there must be at least one instance(empty enum are useless).
 - Instance member of enum must be 
final - Override the 
indexand thehasCodegetters, as well as the== operator - A static or instance member named 
valuesare not allowed, as it would conflict with the default staticvaluesgetter. 
    
Top comments (0)