2010-11-20 7 views
9

Ho già guardato il e case classes vs. Enumeration ma sembra troppo sforzo per troppo meno beneficio.Enumerazioni Scala con oggetti Singleton come elementi di enumerazione e possibilità di scorrere su di essi?

Fondamentalmente mi piacerebbe avere un metodo values restituendo tutti gli oggetti singleton di DayOfWeek senza ripetermi alcune volte.

Ecco come il mio codice dovrebbe essere simile:

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) 

Il metodo values dovrebbe restituire qualcosa come se fosse stata scritta in questo modo:

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

Tutto dovrebbe accadere in MyEnum trait così Ho solo bisogno di estenderlo per ottenere la funzionalità.

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

Qualsiasi suggerimento come questo potrebbe essere fatto esattamente? L'idea è che values accede alla classe e trova tutti gli oggetti singleton della classe che stanno estendendo.

Modifica: Sembra che tutti i suggerimenti non tengano conto che l'utente può anche creare oggetti che dovrebbero ovviamente essere paragonabili a quelli definiti.

Cercherò di fare un altro esempio, forse è più chiaro:

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

voglio avere un tratto (MyEnum), che posso mescolare in oggetto che contiene i miei "oggetti di enumerazione" con metodi per restituirne un elenco (def values: List[MonthDay]) o iterare su di essi (def next: MonthDay o def previous: MonthDay).

PPS: I created a new question for the second part of this question come richiesto da Ken Bloom.

+0

potrebbe ripeti la tua domanda modificata come una nuova domanda (formulata come una domanda di riflessione)? Non ha davvero nulla a che fare con Enumerations. –

+0

la funzione 'add' che ho proposto è ancora una soluzione praticabile alla domanda modificata. –

+0

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

risposta

5

ne dici di questo? Richiede di chiamare effettivamente un metodo add per ogni nuovo valore, ma values restituisce il tipo corretto.

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

È ora possibile chiamare

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

Se avete bisogno di oggetti Singleton che hanno diverse definizioni dei metodi su oggetti diversi, è possibile creare classi anonime in questo modo:

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

Proprio come side point, vuoi usare un 'var' di tipo' List [Value] 'internamente, piuttosto che un' val' di tipo 'Array [Value]', perché vuoi che l'elenco di valori restituiti all'utente sia totalmente immutabile. –

3

scala.Enumeration fa esattamente quello che vuoi già.

penso che si può essere confusi da Scala 2.7 contro 2.8 Scala. La vecchia domanda di citare su emulating Java's enum è stato scritto nei giorni della Scala 2.7, e anche se non posso andare di prova quali funzionalità Scala 2.7 di Enumeration s posessed, Scala 2.8 di Enumeration s certamente in possesso di tutto quello che stai cercando.

Non è possibile definire i valori con object SUNDAY extends Value(1) perchè object s vengono inizializzate pigramente.

+1

No. Ho visto 'scala.Enumeration' e non funziona. Non è possibile aggiungere metodi alla classe corrispondente. Inoltre le istanze istanziate dall'utente di quella classe non sono dello stesso tipo del 'Value's dell'Enumeration. – soc

+2

Sono corretto. Non mi rendevo conto che l'obiettivo era aggiungere metodi definiti dall'utente alla classe 'Value'. –

+0

@soc Non capisco perché pensi di non essere in grado di aggiungere metodi a Val dall'enumerazione. Si prega di vedere il modello C in questa risposta che ho appena postato su un altro thread (e considerare che è possibile aggiungere qualsiasi metodo che si desidera alla classe di casi ChessPieceVal che estende Val: http://stackoverflow.com/a/25923651/501113 – chaotic3quilibrium

2

Il più vicino che ho potuto venire in mente è:

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

non ho capito come cambiare il tipo della variabile _values per catturare la piena tipo Value with Methods.

Problemi correlati