如何向 Dart 中的枚举添加方法或值?

在 Java 中定义枚举时,可以执行类似于下面的操作,即向 enum添加成员。这在达特可行吗?

enum Foo {
one(1), two(2);
final num value;
Foo(this.value);
}
136125 次浏览

在 Dart 中,枚举只能包含枚举项:

enum Color {
red,
green,
blue
}

但是,枚举中的每个项自动有一个与之关联的索引号:

print(Color.red.index);    // 0
print(Color.green.index);  // 1

你可以通过索引号得到这些值:

print(Color.values[0] == Color.red);  // True

见: https://www.dartlang.org/guides/language/language-tour#enums

省道枚举只用于最简单的情况。如果需要更强大或更灵活的枚举,请使用具有静态 const 字段的类,如 https://stackoverflow.com/a/15854550/217408所示

这样你就可以添加任何你需要的东西。

它可能不是“有效的 Dart”,我在 Helper 类中添加了一个静态方法(在 Dart 中没有相应的对象)。

在你的 color.dart文件里

enum Color {
red,
green,
blue
}


class ColorHelper{


static String getValue(Color color){
switch(color){
case Color.red:
return "Red";
case Color.green:
return "Green";
case Color.blue:
return "Blue";
default:
return "";
}
}


}

由于该方法与枚举位于同一个文件中,一次导入就足够了

import 'package:.../color.dart';


...
String colorValue = ColorHelper.getValue(Color.red);

从 Dart 2.6开始,您可以定义类的扩展(包括 Enums)。

enum Cat {
black,
white
}


extension CatExtension on Cat {


String get name {
switch (this) {
case Cat.black:
return 'Mr Black Cat';
case Cat.white:
return 'Ms White Cat';
default:
return null;
}
}


void talk() {
print('meow');
}
}

例如:

Cat cat = Cat.black;
String catName = cat.name;
cat.talk();

这里还有一个实例(使用常量映射代替开关) : Https://dartpad.dartlang.org/c4001d907d6a420cafb2bc2c2507f72c

对于 String 返回值:

enum Routes{
SPLASH_SCREEN,
HOME,
// TODO Add according to your context
}


String namedRoute(Routes route){
final runtimeType = '${route.runtimeTypes.toString()}.';
final output = route.toString();
return output.replaceAll(runtimeType, "");
}

作为对其他使用扩展的建议的改进,您可以在列表或映射中定义分配的值,扩展将是简洁的。

enum Numbers {
one,
two,
three,
}


// Numbers.one.value == 1
// Numbers.two.value == 2
// Numbers.three.value == 3

例子与列表

extension NumbersExtensionList on Numbers {
static const values = [1, 2, 3];
int get value => values[this.index];
}

带有地图的例子

extension NumbersExtensionMap on Numbers {
static const valueMap = const {
Numbers.one: 1,
Numbers.two: 2,
Numbers.three: 3,
};
int get value => valueMap[this];
}

注意: 这种方法有一个限制,那就是你可以在 Enum 上定义一个 静态工厂法静态工厂法,例如 Numbers.create(1)(从 Dart 2.9开始)。您可以在 NumbersExtension上定义这个方法,但是需要像 NumbersExtension.create(1)一样调用它

扩展是好的,但它不能添加静态方法。如果您想要执行类似 MyType.parse (string)的操作,可以考虑使用带有静态 const 字段的类(正如 Günter Zöchbauer 之前建议的那样)。

这里有一个例子

class PaymentMethod {
final String string;
const PaymentMethod._(this.string);


static const online = PaymentMethod._('online');
static const transfer = PaymentMethod._('transfer');
static const cash = PaymentMethod._('cash');


static const values = [online, transfer, cash];


static PaymentMethod parse(String value) {
switch (value) {
case 'online':
return PaymentMethod.online;
break;
case 'transfer':
return PaymentMethod.transfer;
break;
case 'cash':
return PaymentMethod.cash;
default:
print('got error, invalid payment type $value');
return null;
}
}


@override
String toString() {
return 'PaymentMethod.$string';
}
}

我发现这比使用 helper 函数要方便得多。

final method = PaymentMethod.parse('online');
assert(method == PaymentMethod.online);

我这样做了(灵感来自@vovahost 接受的答案)

enum CodeVerifyFlow {
SignUp, Recovery, Settings
}


extension CatExtension on CodeVerifyFlow {
String get name {
return ["sign_up", "recovery", "settings"][index];
}
}


// use it like
CodeVerifyFlow.SignUp.name

回头再谢我!

您可以使用我的包 枚举 _ 可扩展添加额外的字段和方法。
它在枚举上生成扩展,因此您可以以类似于常规 Dart 类的实例的方式使用枚举值。

例如,如果你有 enum MathOperator { plus, minus }symbolcalculate(...)可以添加到它。
因此,枚举可以这样使用:

final n1 = 1;
final n2 = 2.0;
MathOperator.values.forEach((operator) {
print('$n1 ${operator.symbol} $n2 = ${operator.calculate(n1, n2)}');
});

用法:

  1. 向 pubspec.yaml 添加依赖项:

    dependencies:
    enum_extendable_annotation:

    dev_dependencies:
    build_runner:
    enum_extendable_generator:

安装这些依赖项:

# Dart
pub get


# Flutter
flutter packages get
  1. 将导入添加到枚举文件:

    import 'package:enum_extendable_annotation/enum_extendable_annotation.dart';

    part '<your enum file name>.enum_extendable.g.dart';

  2. 创建一个包含所需字段和方法的 PODO 类。

  3. 为每个枚举值创建一个包含此 PODO 类实例的映射。

  4. 注释元素:

  • 具有 @ExtendableEnum()的枚举;
  • PODO 类 -@ExtendableEnumPodo();
  • PODO 实例的映射 -@ExtendableEnumValues()
  1. 运行代码生成器:
  • 如果你的包裹依赖于扑动:

    flutter pub run build_runner build

  • 如果您的软件包不依赖于扑动:

    dart pub run build_runner build

应该生成带有扩展名的文件。

枚举文件示例:

import 'package:enum_extendable_annotation/enum_extendable_annotation.dart';


part 'math_operator.enum_extendable.g.dart';


@ExtendableEnum()
enum MathOperator { plus, minus }


@ExtendableEnumPodo()
class _MathOperatorPodo {


final String symbol;
final num Function(num, num) calculate;


_MathOperatorPodo(
this.symbol,
this.calculate,
);


@ExtendableEnumValues()
static final Map<MathOperator, _MathOperatorPodo> _values = {
MathOperator.plus: _MathOperatorPodo(
'+',
(n1, n2) => n1 + n2,
),
MathOperator.minus: _MathOperatorPodo(
'-',
(n1, n2) => n1 - n2,
),
};
}

Dart 中即将出现一个被称为增强枚举的特性,它允许使用类中已知的许多特性来声明枚举。例如:

enum Blah {
one(1), two(2);
final num value;
const Blah(this.value);
}

这个特性还没有发布(注意,有几个功能还没有正常工作) ,但是可以通过传递 --enable-experiment=enhanced-enums来使用适当的新版本的工具对它进行实验。

结果是 Blah是一个有两个值 Blah.oneBlah.two的枚举声明,我们有 Blah.one.value == 1Blah.two.value == 2。当前的出血边缘在公共前端处理这个例子(因此 dartdart2js将处理它) ,但是它还没有被分析器处理。

省道增强枚举类

从 Dart 2.17开始,引入了 增强的枚举类特性。因此,问题中的例子应该是这样的:

enum Foo {
one(1),
two(2);


const Foo(this.value);
final num value;
}

现在,您可以像下面这样使用枚举类:

void main() {
const foo = Foo.one;
print(foo.value); // 1
}

请注意,您需要更新您的 SDK 约束,因为该特性需要 Dart 2.17:

environment:
sdk: '>=2.17.0-0 <3.0.0'

添加成员

使用增强的枚举,您可以将 任何成员添加到枚举中,只要 构造函数是 const

这也意味着您可以向现有枚举添加 getter 或方法,例如:

enum Cake {
cherry,
apple,
strawberry;


String get description => '$name cake';
}

非专利药

增强的枚举类还允许您为枚举使用泛型。如果您将其与成员组合,则可以执行以下操作:

enum Bar<T extends Object> {
number<int>(42),
name<String>('creativecreatorormaybenot'),
baz(true); // Note that type inference also works.


const Bar(this.value);
final T value;
}

混合和接口

除了声明成员之外,您还可以使用增强的枚举实现 Mixin 和接口,并重写任何缺少的实现。

mixin Foo {
int get n;
}


abstract class Bar {
void printNumber();
}


enum Baz with Foo implements Bar {
one(1),
two(2);
  

const Baz(this.n);


@override
final int n;


@override
void printNumber() => print(n);
}

多次争吵

最后请注意,即使我没有在上面的任何示例中使用它,也可能有任意数量的参数(和初始化器列表) :

enum Foo {
bar(42, description: 'The answer to life, the universe, and everything.'),
baz(0, enabled: false, description: 'noop');


const Foo(
int number, {
this.enabled = true,
required this.description,
}) : n = number;
final int n;
final bool enabled;
final String description;
}