【问题标题】:Scala: Create enumeration object from a setScala:从集合中创建枚举对象
【发布时间】:2016-05-17 19:07:37
【问题描述】:

我想知道是否有任何方法可以从一个集合(例如,一组字符串)中创建一个枚举类。

下面是一个简单的尝试:

val s = Set("v1", "v2", "v3")

object sEnum extends Enumeration {
  for (v <- s) {
    val v = Value
  }
}

for (v <- sEnum.values) {
  println(v)
}

枚举对象似乎可以编译,但它的值很不稳定:打印循环显示 sEnum 中的值如下所示:

因此,问题似乎出在值声明上

val v = Value

有什么方法可以在运行时将变量 v 替换为它的内容(我假设使用反射)?

【问题讨论】:

    标签: scala reflection enumeration


    【解决方案1】:

    TL;DR:看看底部的例子。

    枚举中的值没有字符串名称(尽管它们具有唯一的数字 ID)。枚举值获取字符串名称的方式有两种:

    1. 在调用 Value 时显式传递它,例如Value("v1")
    2. 如果您在类中创建val 字段,Scala 会根据字段名称推断值,例如在val v1 = Value。这是通过反射在内部完成的,方法是检查所有返回符合类型的 0-args 方法。

    第二种情况不适用于您的示例:val v = Value 不会在类上创建 方法v 只是循环内的局部变量(隐藏迭代变量v)。所以你需要采取第一种方法:

    val s = Set("v1", "v2", "v3")
    object MyEnum extends Enumeration {
      s.foreach(Value(_))
    }
    MyEnum.values.foreach(println) // prints v1 v2 v3
    

    现在,这不允许您轻松访问枚举值,MyEnum.v1 将不起作用。无法根据一组字符串值动态地将方法/字段添加到类中。至少在没有一些你可能不想冒险的神奇字节码操作的情况下并非如此。

    相反,您可以定义用于检索值的自定义方法。下面是一个使用Symbols的例子,这样就不用再使用低效的MyEnum.withName()方法了:

    val s = Set("v1", "v2", "v3")
    
    object MyEnum extends Enumeration {
      type MyEnum = Value
      s.foreach(Value(_))
    
      private val constants = s.map(v => Symbol(v) -> withName(v)).toMap
      def apply(c: Symbol): MyEnum = constants(c)
    }
    
    MyEnum.values.foreach(println) // prints v1 v2 v3
    println(MyEnum('v1)) // prints v1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-02
      • 1970-01-01
      相关资源
      最近更新 更多