使用Singleton对象作为枚举元素的Scala枚举以及迭代它们的可能性?

时间:2010-11-20 22:04:12

标签: java reflection scala enums

我已经查看了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])或迭代它们({ {1}}或def next: MonthDay)。

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

3 个答案:

答案 0 :(得分:5)

这个怎么样?它要求您实际为每个新值调用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
    })

答案 1 :(得分:3)

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

我认为你可能会对Scala 2.7和Scala 2.8感到困惑。您引用emulating Java's enum的旧问题是在Scala 2.7的时代编写的,尽管我无法测试Scala 2.7的Enumeration所构成的功能,Scala 2.8的{{1}肯定拥有你正在寻找的一切。

您无法使用Enumeration定义值,因为object SUNDAY extends Value(1)已被懒惰地初始化。

答案 2 :(得分:2)

我能提出的最接近的是:

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