【问题标题】:Scala enumerations with Singleton objects as enumeration elements and a possibility to iterate over them?使用 Singleton 对象作为枚举元素的 Scala 枚举以及迭代它们的可能性?
【发布时间】:2011-05-13 05:23:03
【问题描述】:

我已经看过Scala question about emulating Java's enumcase classes vs. Enumeration,但似乎付出了太多的努力却收获了太少。

基本上,我希望有一个 values 方法返回 DayOfWeek 的所有单例对象,而无需重复几次。

我的代码应该是这样的:

object DayOfWeek extends MyEnum {
  object MONDAY extends DayOfWeek(1)
  object TUESDAY extends DayOfWeek(2)
  object WEDNESDAY extends DayOfWeek(3)
  object THURSDAY extends DayOfWeek(4)
  object FRIDAY extends DayOfWeek(5)
  object SATURDAY extends DayOfWeek(6)
  object SUNDAY extends DayOfWeek(7)
}

class DayOfWeek(ordinal: Int)

values 方法应该返回类似这样的写法:

val values = Array(MONDAY, TUESDAY, WEDNESDAY, THURSDAY,
                   FRIDAY, SATURDAY, SUNDAY)

一切都应该发生在 MyEnum 特征中,所以我只需要扩展它即可获得功能。

trait MyEnum {
  val values = this.getClass.getField("MODULE$") etc. etc.
}

有什么建议可以做到这一点吗? 这个想法是values 访问该类并找到它们正在扩展的类的所有单例对象。

编辑:似乎所有建议都没有考虑到用户也可以创建对象,这些对象当然应该与定义的对象相当。

我再举一个例子,也许更清楚:

object MonthDay extends MyEnum {
  //Some important holidays
  object NewYear       extends MonthDay( 1,  1)
  object UnityDay      extends MonthDay(11,  9)
  object SaintNicholas extends MonthDay(12,  6)
  object Christmas     extends MonthDay(12, 24)
}

class MonthDay(month: Int, day: Int)

//Of course the user can create other MonthDays
val myBirthDay = new MonthDay(month, day)

if(!MonthDay.values.contains(myBirthDay)) "Well, I probably have to work"
else "Great, it is a holiday!"

我想要一个特征 (MyEnum),我可以将它混合到包含我的“枚举对象”的对象中,并使用返回它们列表的方法 (def values: List[MonthDay]) 或迭代它们 (def next: MonthDay 或 @ 987654338@).

PPS:I created a new question for the second part of this question 应 Ken Bloom 的要求。

【问题讨论】:

  • 您能否将修改后的问题作为新问题重新提出(表述为反思问题)?它确实与枚举无关。
  • 我提出的add 函数仍然是您修改后问题的可行解决方案。
  • @Ken Bloom:完成,这里是:stackoverflow.com/questions/4239594/…

标签: java reflection scala enums


【解决方案1】:

这个怎么样?它要求您为每个新值实际调用 add 方法,但 values 返回正确的类型。

abstract class MyEnum{

   type Value     //define me to be the value type for this MyEnum

   private var _values:List[Value] = Nil
   def values = _values    
   protected def add(newValue:Value) = {
      _values = newValue::_values
      newValue
   }
}

object DayOfWeek extends MyEnum{
   class Value(val dayNum:Int)
   val SUNDAY    = add(new Value(1))
   val MONDAY    = add(new Value(2))
   val TUESDAY   = add(new Value(3))
   val WEDNESDAY = add(new Value(4))
   val THURSDAY  = add(new Value(5))
   val FRIDAY    = add(new Value(6))
   val SATURDAY  = add(new Value(7))
}

你现在可以打电话了

println(DayOfWeek.values map (_.dayNum))

如果您需要对不同对象的方法有不同定义的单例对象,您可以像这样创建匿名类:

add(new Value{
      override def dayNum=8
    })

【讨论】:

  • 顺便说一句,您希望在内部使用List[Value] 类型的var,而不是Array[Value] 类型的val,因为您希望将值列表返回到用户是完全不可变的。
【解决方案2】:

scala.Enumeration 完全符合您的要求。

我认为您可能对 Scala 2.7 和 Scala 2.8 感到困惑。你引用的关于 emulating Java's enum 的老问题是在 Scala 2.7 时代编写的,虽然我无法测试 Scala 2.7 的 Enumerations 拥有什么功能,但 Scala 2.8 的 Enumerations 肯定拥有你的一切正在寻找。

您不能用object SUNDAY extends Value(1) 定义值,因为objects 是延迟初始化的。

【讨论】:

  • 没有。我查看了scala.Enumeration,但它不起作用。无法将方法添加到相应的类。此外,该类的用户实例化实例与枚举中的Values 类型不同。
  • 我的立场是正确的。我没有意识到目标是将用户定义的方法添加到 Value 类。
  • @soc 我不明白你为什么认为你无法通过枚举向 Val 添加方法。请在我刚刚发布到另一个线程的这个答案中查看模式 C(并考虑您可以将任何您喜欢的方法添加到扩展 Val 的案例类 ChessPieceVal:stackoverflow.com/a/25923651/501113
【解决方案3】:

我能想到的最接近的是:

abstract class MyEnum(val displayName:String){
   protected object Value{
      var _values:List[Value] = Nil
      def values = _values
   }
   protected class Value (val value:Int){
      Value._values = this::Value._values
      override def toString = "%s(%d)".format(displayName,value)
   }
   def values = Value.values
}

trait Methods{
   def dayName
}

object DayOfWeek extends MyEnum("DayOfWeek"){
   val SUNDAY = new Value(1) with Methods{
      override def dayName = "Sunday"
   }
   val MONDAY = new Value(2) with Methods{
      override def dayName = "Monday"
   }
   val TUESDAY = new Value(3) with Methods{
      override def dayName = "Tuesday"
   }
   val WEDNESDAY = new Value(4) with Methods{
      override def dayName = "Wednesday"
   }
   val THURSDAY = new Value(5) with Methods{
      override def dayName = "Thursday"
   }
   val FRIDAY = new Value(6) with Methods{
      override def dayName = "Friday"
   }
   val SATURDAY = new Value(7) with Methods{
      override def dayName = "Saturday"
   }
}

我还没有弄清楚如何更改_values 变量的类型以捕获完整类型Value with Methods

【讨论】:

    猜你喜欢
    • 2013-09-03
    • 2018-09-07
    • 2011-02-07
    • 2021-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    相关资源
    最近更新 更多