2013-08-12 9 views
7

Ho una classe di casi che memorizza tre parametri associati. Mi piacerebbe definire oggetto associato che possono costruire la classe da qualsiasi coppia di parametri, qualcosa che assomiglia alla esempio riportato di seguito, che è ovviamente sbagliato:definire argomenti con nome predefinito in termini di altri argomenti in scala

def test(start : Float = end - duration, duration : Float = end - start, end : Float = start + duration) { 
    require(abs(start + duration - end) < epsilon) 
    ... 
} 
val t1 = test(start = 0f, duration = 5f) 
val t2 = test(end = 4f, duration = 3f) 
val t3 = test(start = 3f, end = 5f) 

Quali trucchi posso usare per ottenere la sintassi utilizzo simile?

risposta

26

È possibile utilizzare Tipo-classi:

// Represents no argument 
object NoArg 

// Resolves start, duration, stop 
trait DurationRes[A,B,C] { 
    def resolve(s: A, d: B, e: C): (Float, Float, Float) 
} 

object DurationRes { 
    implicit object startEndRes extends DurationRes[Float, NoArg.type, Float] { 
    def resolve(s: Float, d: NoArg.type, e: Float) = (s, e-s, e) 
    } 
    implicit object startDurRes extends DurationRes[Float, Float, NoArg.type] { 
    def resolve(s: Float, d: Float, e: NoArg.type) = (s, d, s+d) 
    } 
    // etc. 
} 

def test[A,B,C](start: A = NoArg, dur: B = NoArg, end: C = NoArg) 
       (implicit res: DurationRes[A,B,C]) { 
    val (s,d,e) = res.resolve(start, dur, end) 
    // s is start, d duration, e end 
} 

test(start = 1f, end = 2f) 

questo modo è anche type-safe e non si può chiamare qualcosa come:

test(start = 1f) 

o anche

test() 
3

Dopo un po 'pensando che sono arrivato con un'altra soluzione (non dico che sia meglio, vorrei solo sapere se è un approccio accettabile). L'essenza è quella di definire una classe: class Klass(val x: Int, val y: Int, val z: Int) e un oggetto associato:

object Klass { 
    def apply(x: Int, y: Int)(z: Int = x + y) = { 
    new Klass(x, y, z) 
    } 
    // and so on 
} 

Così si può poi fare val k = Klass(x = 5, y = 6)() e ottenere val k per riferirsi a Klass(5, 6, 11) esempio.

E a causa della quantità di codice ridotta, è possibile definire una macro per eseguire il lavoro, ma per me è un po 'difficile per ora, ma è comunque un esercizio interessante.

Aggiornamento

Dopo qualche tempo, mi piacerebbe sottolineare a voi che ci sono solo tre combinazioni di parametri nel tuo caso, in modo da non sarebbe solo più facile per fornire 3 apply() metodi a mano ? apply(s, d), apply(s, e), apply(d, e) dovrebbe essere sufficiente per le tue esigenze. E questo ti farà risparmiare un po 'di battitura, perché con altri approcci, in pratica, devi codificare anche tutti i casi.

+0

Nota che questo funziona solo se i tuoi argomenti hanno tipi diversi. Non è possibile sovraccaricare 'apply' in questo modo a causa della compatibilità con Java. (In Java i nomi degli argomenti non fanno parte dell'interfaccia pubblica). – gzm0

Problemi correlati