2010-11-20 5 views
9

Ya miré y case classes vs. Enumeration pero parece demasiado esfuerzo para obtener un beneficio menor.Enumeraciones Scala con objetos Singleton como elementos de enumeración y la posibilidad de iterar sobre ellos?

Básicamente me gustaría tener un método values devolviendo todos los objetos simples de DayOfWeek sin repetirme algunas veces.

Así es como mi código debería ser similar:

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) 

El método values debe devolver algo así como si hubiera sido escrito así:

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

Todo debe suceder en el rasgo MyEnum por lo Solo necesito extenderlo para obtener la funcionalidad.

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

¿Alguna sugerencia de cómo se puede hacer esto exactamente? La idea es que values acceda a la clase y encuentre todos los objetos únicos de la clase que están extendiendo.

Editar: Parece que todas las sugerencias no tienen en cuenta que el usuario también puede crear objetos que, por supuesto, deben ser comparables a los definidos.

Voy a tratar de dar otro ejemplo, tal vez es más claro:

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!" 

Quiero tener un rasgo (MyEnum) que puedo mezclar en el objeto que sostiene mis "objetos" de enumeración con métodos para devolver una lista de ellos (def values: List[MonthDay]) o iterar sobre ellos (def next: MonthDay o def previous: MonthDay).

PPS: I created a new question for the second part of this question según lo solicitado por Ken Bloom.

+0

podría vuelva a hacer su pregunta modificada como una nueva pregunta (expresada como una pregunta de reflexión)? Realmente no tiene nada que ver con Enumerations. –

+0

la función 'agregar' que he propuesto sigue siendo una solución factible para su pregunta modificada. –

+0

@Ken Bloom: listo, aquí está: http://stackoverflow.com/questions/4239594/how-to-access-objects-within-an-object-by-mixing-in-a-trait-with-reflection – soc

Respuesta

5

¿Qué le parece esto? Requiere que realmente llame a un método add para cada nuevo valor, pero values devuelve el tipo correcto.

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)) 
} 

Ahora puede llamar

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

Si necesita objetos únicos que tienen diferentes definiciones de los métodos en diferentes objetos, puede crear clases anónimas, así:

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

Solo como punto lateral, quiere usar una 'var' de tipo' List [Value] 'internamente, en lugar de' val' de tipo 'Array [Value]', porque quiere que la lista de valores devuelta al usuario sea totalmente inmutable. –

3

scala.Enumeration hace exactamente lo que quiere.

Creo que puede ser confundido por Scala 2.7 frente a Scala 2.8. La vieja pregunta que citas sobre emulating Java's enum fue escrita en los días de Scala 2.7, y aunque no puedo probar qué funcionalidad tienen los Enumeration s de Scala 2.7, los Enumeration de Scala 2.8 ciertamente poseen todo lo que estás buscando.

No se pueden definir valores con object SUNDAY extends Value(1) porque object s se inicializan de forma perezosa.

+1

No. Miré 'scala.Enumeration' y no funciona. No es posible agregar métodos a la clase correspondiente. Además, las instancias instanciadas por el usuario de esa clase no son del mismo tipo que los 'Value's de la Enumeración. – soc

+2

Estoy parado. No me di cuenta de que el objetivo era agregar métodos definidos por el usuario a la clase 'Value'. –

+0

@soc No entiendo por qué cree que no puede agregar métodos a Val de la enumeración. Consulte el patrón C en esta respuesta que acabo de publicar en otro hilo (y considere que puede agregar cualquier método que desee a la clase de caso ChessPieceVal que amplía Val: http://stackoverflow.com/a/25923651/501113 – chaotic3quilibrium

2

Lo más cerca que he sido capaz de llegar a decir:

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" 
    } 
} 

no he descubierto la manera de cambiar el tipo de la variable _values para capturar el pleno tipo Value with Methods.

Cuestiones relacionadas