2013-08-12 14 views
7

Ich habe eine Fall-Klasse, die drei gebundene Parameter speichert. Ich mag Begleiter Objekt definieren, die die Klasse von zwei beliebigen Parametern bauen können, etwas, das unten wie die Probe aussieht, das ist offensichtlich falsch:define benannte Argumente in Bezug auf andere Argumente in scala definieren

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) 

Welche Tricks, die ich verwenden kann ähnliche Verwendungssyntax zu bekommen?

Antwort

26

Sie können Typ-Klassen verwenden:

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

Auf diese Weise ist es auch typsicher und man kann nicht so etwas wie nennen:

test(start = 1f) 

oder sogar

test() 
3

Nach ein wenig denke, dass ich mit einer anderen Lösung gekommen bin (ich behaupte nicht, dass es besser ist, würde nur gerne wissen, ob es überhaupt akzeptabel ist)). Das Wesentliche ist, eine Klasse zu definieren: class Klass(val x: Int, val y: Int, val z: Int) und ein Begleitobjekt:

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

So können Sie dann val k = Klass(x = 5, y = 6)() tun und bekommen val k-Klass(5, 6, 11) Instanz zu verweisen.

Und wegen der kleinen Codemenge kann man wohl Makros definieren, um das zu machen, aber das ist ein bisschen schwierig für mich, aber es ist eine interessante Übung.

aktualisieren

Nach einiger Zeit, würde Ich mag Ihnen zu beachten, dass es nur drei Kombinationen von Parametern in Ihrem Fall sind, so wäre es nicht nur einfacher sein, um 3 apply() Methoden von Hand ? sollte Ihre Bedürfnisse erfüllen. Und das wird Ihnen ein wenig Tipparbeit ersparen, denn bei anderen Ansätzen müssen Sie grundsätzlich auch alle Fälle codieren.

+0

Beachten Sie, dass dies nur funktioniert, wenn Ihre Argumente unterschiedliche Typen haben. Sie können 'apply' aufgrund der Java-Kompatibilität nicht überladen. (In Java sind die Argumentnamen nicht Teil der öffentlichen Schnittstelle). – gzm0

Verwandte Themen