Перечисления Scala с объектами Singleton в качестве элементов перечисления и возможность их перебирать? - PullRequest
9 голосов
/ 21 ноября 2010

Я уже рассматривал вопрос Scala об эмуляции Java * enum и классов падежей и перечисления , но, похоже, слишком много усилий для слишком меньшей выгоды.

В основном я хотел бы иметь метод 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 или *). 1036 *).

PPS: Я создал новый вопрос для второй части этого вопроса в соответствии с просьбой Кена Блума.

Ответы [ 3 ]

5 голосов
/ 21 ноября 2010

Как насчет этого?Это требует от вас фактического вызова метода 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
    })
3 голосов
/ 21 ноября 2010

scala.Enumeration делает именно то, что вы уже хотите.

Я думаю, вы можете быть смущены Scala 2.7 против Scala 2.8.Старый вопрос, который вы цитируете о эмуляции Java enum, был написан во времена Scala 2.7, и хотя я не могу проверить, какие функциональные возможности у Scala 2.7 Enumeration имеются, у Scala 2.8Enumeration s, безусловно, обладают всем, что вы ищете.

Вы не можете определять значения с помощью object SUNDAY extends Value(1), потому что object s инициализируются лениво.

2 голосов
/ 21 ноября 2010

Самое близкое, что я смог придумать, это:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...