Dart如何获得枚举的“值”


83

在Dart中提供枚举之前,我编写了一些麻烦且难以维护的代码来模拟枚举,现在想简化它。我需要以字符串形式获取枚举的值,例如可以用Java完成但不能。

例如,在每种情况下,当我想要的是“ MONDAY”时,很少的测试代码片段返回“ day.MONDAY”

enum day {MONDAY, TUESDAY}
print( 'Today is $day.MONDAY');
print( 'Today is $day.MONDAY.toString()');

我是否正确,只需要解析“ MONDAY”字符串即可?


而且没有迭代器?
内特·洛克伍德

1
Dart提供获取值describeEnum的方法,请参见示例stackoverflow.com/a/60615370/11827756
Kalpesh Dabhi

Dart需要类似“名称”的内置属性来减少所有这种愚蠢(例如,day.MONDAY.name)。
皮特·阿尔文

Answers:


53

不幸的是,您正确的是toString方法返回"day.MONDAY",而不是更有用"MONDAY"。您可以通过以下方式获取字符串的其余部分:

day theDay = day.MONDAY;      
print(theDay.toString().substring(theDay.toString().indexOf('.') + 1));

诚然,这不太方便。

如果要迭代所有值,可以使用day.values

for (day theDay in day.values) {
  print(theDay);
}

1
枚举stackoverflow.com/questions/15854549的旧方法提供了更大的灵活性,但不能用作常量。创建一个库并使用前缀导入它可以解决此问题(请参见stackoverflow.com/a/15855913/217408上面的内联问题中的此答案)。
君特Zöchbauer

将“枚举类”实例用作常量有什么问题?
lrn

创建类的const实例并将它们用作静态const成员应该没有任何问题-这就是语言枚举实现所要做的:class MyEnum { static const MyEnum someItem = const MyEnum(0); static const MyEnum someOtherItem = const MyEnum(1); final int id; const MyEnum(this.id); }
lrn 2015年

@Irm我能够重写和测试我需要的几种方法。也许枚举会延长一天以提供名称作为字符串。
Nate Lockwood

@lrn我试过了,它奏效了。感谢您指出了这一点。我最后一次尝试我在得到一个错误doSomething1([Status status = Status.off]) { DartPad
君特Zöchbauer

102

短一点:

String day = theDay.toString().split('.').last;

9
更简单的方法:theDay.toString()。split('。')。last
Hani

1
谢谢,@ Hani!您的改进既简单又“安全”。更新了答案。
Jannie Theunissen

101

Dart 2.7带有称为扩展方法的新功能。现在,您可以像这样简单地为Enum编写自己的方法!

enum Day { monday, tuesday }

extension ParseToString on Day {
  String toShortString() {
    return this.toString().split('.').last;
  }
}

main() {
  Day monday = Day.monday;
  print(monday.toShortString()); //prints 'monday'
}

如此处所述,尽管枚举已正确导入,但我无法使用其他文件中的扩展名。当我按照doc示例向扩展名添加名称时,它起作用了:“ extension Formatting on Day”。如果不是我,也许可以编辑。还应使用Jannie和mbartn响应的组合来更新响应。
ko0stik'4

1
我还原了上一次的编辑更改,因为没有扩展名,该更改无法正常工作

这不是最好的解决方案。Kalpesh Dabhi在这里提供了更好的解决方案:stackoverflow.com/a/60615370/9695154
Gustavo Rodrigues

describeEnum是仅Flutter的方法,要在Dart中获取枚举的值很重要,因为它很
受欢迎

52

获取枚举名称的最简单方法是flutter / foundation.dart中的标准方法

describeEnum(enumObject)

enum Day {
  monday, tuesday, wednesday, thursday, friday, saturday, sunday
}

void validateDescribeEnum() {
  assert(Day.monday.toString() == 'Day.monday');
  assert(describeEnum(Day.monday) == 'monday');
}

8
这只能在Flutter中使用。对于仅dart代码(使用dart而不是flart运行),将导致错误。
罗恩

21

有一个更优雅的解决方案:

enum SomeStatus {
  element1,
  element2,
  element3,
  element4,
}

const Map<SomeStatus, String> SomeStatusName = {
  SomeStatus.element1: "Element 1",
  SomeStatus.element2: "Element 2",
  SomeStatus.element3: "Element 3",
  SomeStatus.element4: "Element 4",
};

print(SomeStatusName[SomeStatus.element2]) // prints: "Element 2"

14
你叫它优雅吗?怎么样?通过添加额外的空间到内存和20条新行?
GensaGames

2
这实际上是一种反模式。当您需要为枚举添加更多值时,您需要在两个位置修改代码,因为您也应该修改映射。想象一下,如果您在一个大型应用程序中有数百个枚举,并且在应用程序的不同部分有数百张地图。很难维护。
丹尼尔·莱森

4
我真的很喜欢这样。其他解决方案似乎很棘手。
托尼

10

这是您的枚举:

enum Day {
  monday,
  tuesday,
}

创建扩展名(可能需要import 'package:flutter/foundation.dart';

extension DayEx on Day {
  String get inString => describeEnum(this);
}

用法:

void main() {
  Day monday = Day.monday;
  String inString = monday.inString; // 'monday'
}

1
利用describeEnum是要走的路。使用扩展名是一项巧妙的奖励
Pierrea

6

我使用下面的函数来获取枚举值的名称,反之亦然,通过名称获取枚举值:

String enumValueToString(Object o) => o.toString().split('.').last;

T enumValueFromString<T>(String key, Iterable<T> values) => values.firstWhere(
      (v) => v != null && key == enumValueToString(v),
      orElse: () => null,
    );

当使用Dart 2.7及更高版本时,扩展方法将在此处(以及其他任何对象)起作用:

extension EnumX on Object {
  String asString() => toString().split('.').last;
}

上面的实现不依赖于特定的枚举。

用法示例:

enum Fruits {avocado, banana, orange}
...
final banana = enumValueFromString('banana', Fruits.values);
print(enumValueToString(banana)); // prints: "banana"
print(banana.asString()); // prints: "banana"

从2020-04-05编辑:添加了可空性检查。values参数可以是Iterable,不一定是List。添加了扩展方法实现。<Fruits>从示例中删除了注释,以表明不需要类名重复。


感谢您分享亚历山大!这正是我所寻找的;-)
Rohanthewiz

交易枚举的最佳答案
Mahmoud Abu Elheja'4


2

我使用如下结构:

class Strings {
  static const angry = "Dammit!";
  static const happy = "Yay!";
  static const sad = "QQ";
}

2

我的方法没有根本不同,但在某些情况下可能会稍微方便一些:

enum Day {
  monday,
  tuesday,
}

String dayToString(Day d) {
  return '$d'.split('.').last;
}

在Dart中,您无法自定义枚举的 toString方法,因此我认为此助手功能的解决方法是必要的,并且它是最佳方法之一。如果您希望在这种情况下更正确,则可以将返回的字符串的首字母大写。

您还可以添加一个dayFromString功能

Day dayFromString(String s) {
  return Day.values.firstWhere((v) => dayToString(v) == s);
}

用法示例:

void main() {
  Day today = Day.monday;
  print('Today is: ${dayToString(today)}');
  Day tomorrow = dayFromString("tuesday");
  print(tomorrow is Day);
}

2
enum day {MONDAY, TUESDAY}
print( 'Today is ${describeEnum(day.MONDAY)}' );

控制台输出:今天是星期一


1

我在一个项目中遇到了同样的问题,现有的解决方案不是很干净,并且不支持json序列化/反序列化等高级功能。

Flutter本机目前不支持带有值的枚举,但是,我设法Vnum使用类和反射器实现来开发一个帮助程序包,以解决此问题。

地址到存储库:

https://github.com/AmirKamali/Flutter_Vnum

要使用回答您的问题Vnum,您可以按以下方式实现代码:

@VnumDefinition
class Visibility extends Vnum<String> {
  static const VISIBLE = const Visibility.define("VISIBLE");
  static const COLLAPSED = const Visibility.define("COLLAPSED");
  static const HIDDEN = const Visibility.define("HIDDEN");

  const Visibility.define(String fromValue) : super.define(fromValue);
  factory Visibility(String value) => Vnum.fromValue(value,Visibility);
}

您可以像这样使用它:

var visibility = Visibility('COLLAPSED');
print(visibility.value);

github存储库中有更多文档,希望对您有所帮助。


1
enum day {MONDAY, TUESDAY}
print(day.toString().split('.')[1]);
OR
print(day.toString().split('.').last);

1

除了为每个枚举定义扩展名,我们还可以为对象定义扩展名并.enumValue从任何枚举中访问。

void main() {

  // ❌ Without Extension ❌

  print(Countries.Cote_d_Ivoire.toString().split('.').last.replaceAll("_", " ")); // Cote d Ivoire
  print(Movies.Romance.toString().split('.').last.replaceAll("_", " ")); //Romance


  // ✅ With Extension ✅

  print(Countries.Cote_d_Ivoire.enumValue); // Cote d Ivoire
  print(Movies.Romance.enumValue); //Romance
}

enum Countries { United_States, United_Kingdom, Germany, Japan, Cote_d_Ivoire }
enum Movies { Romance, Science_Fiction, Romantic_Comedy, Martial_arts }

extension PrettyEnum on Object {
  String get enumValue => this.toString().split('.').last.replaceAll("_", " ");
}

这样,您甚至可以定义多单词枚举,其中单词的名称之间用_(下划线)分隔。


1

创建一个类来帮助:

class Enum {
    Enum._();

    static String name(value) {
        return value.toString().split('.').last;
    }
}

并致电:

Enum.name(myEnumValue);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.