2012-10-07 15 views
17

Ich versuche, eine Klasse mit einigen Methoden nehmen einen impliziten Parameter zur Verfügung zu stellen, um zu definieren:Wie Standardwert für implizite Parameter in den Klassen

object Greetings { 
    def say(name: String)(implicit greetings: String): String = greetings + " " +name 
} 

ich diese Klasse von einer anderen Klasse verwende

implicit val greetings = "hello"    //> greetings : java.lang.String = hello 
Greetings.say("loic")       //> res0: String = hello loic 
Greetings.say("loic")("hi")      //> res1: String = hi loic 

Mein Problem ist, dass es nur funktioniert, wenn ich das implizite Wert außerhalb meines Greetings-Objekts definiere. Ich möchte in der Lage sein, Methoden mit impliziten Parametern mit einem Standardwert innerhalb meiner Klasse bereitzustellen, um die Verwendung meiner API (wie Scala Collection API) zu erleichtern.

So würde Ich mag, dies zu tun, aber es funktioniert nicht (impliziter Wert nicht gefunden):

object Greetings { 
    implicit val greetings = "hello"  
    def say(name: String)(implicit greetings: String): String = greetings + " " +name 
} 

und dann

Greetings.say("loic")       
Greetings.say("loic")("hi") 

Ich weiß, ich kann einen Standardwert mit (implicit greetings: String = "hello") definieren, aber Ich würde es gerne auf Klassenebene machen, um zu vermeiden, dass es viele Methoden gibt.

Ich denke, ich vermisse etwas, weil ich sah, dass CanBuildFrom zum Beispiel innerhalb der List Klasse definiert ist.

Antwort

6

Ich habe eine Abhilfe gefunden:

class Greetings(implicit val greetings: String = "hello") { 
    def say(name: String): String = greetings + " " + name 
} 

Wie das kann ich einen Standardwert haben und sie außer Kraft setzen, wenn ich will:

new Greetings().say("loic")      //> res0: String = hello loic 

implicit val greetings = "hi"     //> greetings : java.lang.String = hi 
new Greetings().say("loic")      //> res1: String = hi loic 

new Greetings()("coucou").say("loic")   //> res2: String = coucou loic 

Hinweis: new Greetings()("coucou") arbeitet, nicht new Greetings("coucou"), weil einer Syntax Strangeness erklärt here.

+0

es nicht seltsam ist, da implizit nur Sekunden, um die normalen Parameter eingefügt werden. Normalerweise würde Ihre Klasse wie 'class Greetings() aussehen (implizite val ...)' – thatsIch

24

Es ist eine schlechte Idee, einen allgemeinen Typ wie String in einem impliziten zu verwenden. Der Hauptgrund ist, dass die implizite Suche ausschließlich auf dem Typ basiert. Was also, wenn jemand anders einen anderen impliziten Wert vom Typ String definiert? Sie könnten mit einem Konflikt enden. Sie sollten also Ihren eigenen spezifischen Typ für Ihren eigenen Zweck definieren (einen einfachen Wrapper um String).

Ein weiterer Grund ist, dass der Compiler bei der Suche nach impliziten Werten (unter anderem) nach dem Companion-Objekt (falls vorhanden) des impliziten Wertetyps sucht. Sie können leicht sehen, wie nützlich es ist, da das Begleitobjekt der natürliche Ort ist, um einen standardmäßigen impliziten Wert zu setzen (wie in Ihrem Fall). Aber wenn der implizite Wert von einem Typ ist, den Sie nicht besitzen (wie String), können Sie einfach kein Begleitobjekt dafür schreiben, während bei Ihrem eigenen Wrappertyp kein Problem besteht.

OK, genug Wortschwall, hier ist, wie Sie es tun können:

case class Greetings(value: String) { 
    override def toString = value 
} 
object Greetings { 
    // this implicit is just so that we don't have to manually wrap 
    // the string when explicitly passing a Greetings instance 
    implicit def stringToGreetings(value: String) = Greetings(value) 

    // default implicit Greetings value 
    implicit val greetings: Greetings ="hello" 

    def say(name: String)(implicit greetings: Greetings): String = greetings + " " +name 
} 
Greetings.say("loic")       
Greetings.say("loic")("hi") 
+0

Ok, ich bekomme es, vielen Dank :) – Loic

Verwandte Themen