【问题标题】:Scala class that handles enumerations generically一般处理枚举的 Scala 类
【发布时间】:2013-01-05 05:54:43
【问题描述】:

我想创建一个通用类来保存枚举的值,并且还允许访问枚举的可能值。以属性编辑器为例——您需要知道该属性的当前值,并且您还需要能够知道该属性还有哪些其他值是合法的。并且不应该事先知道枚举的类型,您应该能够使用任何类型的枚举。

我的第一个想法是这样的:

class EnumerationProperty[T <: Enumeration](value:T)

但是,这不起作用,因为对于枚举 T 不是类型,它是一个对象。我尝试过的其他变体是:

class EnumerationProperty[T <: Enumeration](value:T.Value)
class EnumerationProperty[T <: Enumeration.Value](value:T)

(我不会详细说明为什么这些不起作用,因为我怀疑原因并不有趣。)

【问题讨论】:

    标签: scala generics types parameters enums


    【解决方案1】:

    对于您问题的第一部分。您可以像这样为通用枚举值定义持有者:

    case class EnumerationProperty[T <: Enumeration#Value](value:T)
    

    但我不知道如何在不显式传递 Enumeration 对象的情况下获取所有枚举值。枚举有values() 方法来获取所有值。并且 Enumeration#Value 具有指向 Enumeration 的链接,但具有私有访问权限

    【讨论】:

      【解决方案2】:

      在您的用例(属性编辑器)中,我认为最好的解决方案是依赖 scala 2.10 中可用的 scala 反射。给定一个类的TypeTag,您可以获得其所有成员的完整类型(无需擦除)以及它们的值,并从中填充您的属性编辑器。对于枚举,使用TypeTag 使用以下方法获取它们的值: Using Scala 2.10 reflection how can I list the values of Enumeration?


      现在,也许你不想或不能使用 scala 反射,从现在开始我会假设是这种情况。如果这是真的,那么你正在打开一整罐蠕虫:) TL;DR:这是不可能使用标准的Enumeration,所以你可能不得不明确地包装枚举值,如 Ptharien 的 Flame 的答案所示(或滚动你自己的 Enumeration )。下面我详细介绍我的所有尝试,请多多包涵。

      不幸的是,出于某种未知的原因(尽管我怀疑这与序列化问题有关),Enumeration.Value 没有指向其Enumeration 实例的字段。鉴于Enumeration 是如何实现的,这将是微不足道的实现,但我们当然没有发言权,除了分叉枚举和修改我们的版本(这实际上是我为此目的所做的,加上对序列化和添加适当的支持)反思——但我离题了)。

      如果我们不能修改Enumeration,也许我们可以扩展它?再次查看实现,这样的事情似乎可行:

      class EnumerationEx extends Enumeration {
        protected class ValEx(i: Int, name: String) extends Val(i, name) {
          @transient val enum: Enumeration = EnumerationEx.this
        }
        override protected def Value(i: Int, name: String): Value = new ValEx(i, name)  
      }
      
      object Colors extends EnumerationEx {
        val Red, Green, Blue = Value
      }
      

      缺点是它只适用于明确扩展EnumerationEx 而不是Enumeration 的枚举,但总比没有好。

      不幸的是,这并不能编译,因为def Value ...Enumeration 中被声明为final,所以没有办法覆盖它。 (再次注意,分叉Enumeration 可以规避这一点。实际上,为什么不这样做,因为我们已经走上了使用自定义枚举的道路。我会让你判断)。

      所以这是另一种看法:

      class EnumerationEx extends Enumeration {
        class ValueWithEnum( inner: Value ) {
          @transient val enum: Enumeration = EnumerationEx.this
        }
        implicit def valueToValue( value: Value ): ValueWithEnum = new ValueWithEnum( value )
      }
      

      确实它可以正常工作。或者看起来是这样。

      scala> object Colors extends EnumerationEx {
           |   val Red, Green, Blue = Value
           | }
      defined module Colors
      
      scala> val red = Colors.Red
      red: Colors.Value = Red
      
      scala> red.enum.values
      res58: Enumeration#ValueSet = Colors.ValueSet(Red, Green, Blue)
      

      万岁?不,因为从ValueValueWithEnum 的转换仅在访问red.enum 时完成,而不是在Colors 枚举的实例化时完成。换句话说,当调用enum 时,编译器需要知道枚举的确切静态类型(编译器必须静态知道red 的类型是Colors.Value,而不仅仅是Enumeration# Value)。而在你提到的用例(属性编辑器)中,你只能依靠java反射(我已经假设你不会使用scala反射)来获取枚举值的类型,而java反射只会给你@987654345 @(扩展 Enumeration#Value)作为 Colors.Red 的类型。所以基本上你被困在这里。 最好的选择肯定是首先使用 scala 反射。

      【讨论】:

      • 在这种情况下,我可以使用 Scala 反射或子类枚举 Enumeration - 很高兴在这种情况下,我只对编辑 Scala 对象的属性感兴趣,而不是 Java 对象。听起来反射是更好的方法,尽管我需要检查我的 scala 版本。
      【解决方案3】:
      class EnumProps[E <: Enumeration](val e: E)(init: e.Value) {...}
      

      那么你就可以使用ee.Value来实现类了。

      【讨论】:

        猜你喜欢
        • 2012-06-19
        • 2012-01-26
        • 2014-09-04
        • 1970-01-01
        • 1970-01-01
        • 2017-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多