2012-10-07 9 views
17

próbuję zdefiniować klasę niektóre metody podejmowania niejawny parametr:Jak zapewnić domyślną wartość parametrów ukrytych na poziomie klasy

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

Używam tej klasy z innej klasy

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

Mój problem polega na tym, że działa tylko wtedy, gdy definiuję niejawną wartość val poza moim obiektem Greetings. Chciałbym móc dostarczyć metody z niejawnymi parametrami, z wartością domyślną w mojej klasie, aby ułatwić korzystanie z mojego API (np. API Scala collection).

Tak chciałbym to zrobić, ale to nie działa (wartość niejawna nie znaleziono):

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

a następnie

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

wiem, że mogę określić wartość domyślną z (implicit greetings: String = "hello") ale Chciałbym to zrobić na poziomie klasy, aby uniknąć powtarzania, jeśli istnieje wiele metod.

Chyba brakuje mi czegoś, ponieważ zobaczyłem, że klasa CanBuildFrom jest zdefiniowana na przykład w klasie List.

Odpowiedz

6

Znalazłem rozwiązania:

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

Jak to mogę mieć wartość domyślną i zastąpić go, jeśli chcę:

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 

Uwaga: new Greetings()("coucou") pracuje, nie new Greetings("coucou"), ponieważ dziwności składni wyjaśnił here.

+0

To nie jest dziwne, ponieważ ukryte zostanie wstawiony tylko sekundy do normalnych parametrów. Zwykle twoja klasa wyglądałaby jak "klasa Greetings() (domyślna wartość ...)" – thatsIch

24

Jest to zły pomysł, aby użyć takiego ogólnego typu jak String w niejawna. Głównym powodem jest to, że wyszukiwanie niejawne jest oparte wyłącznie na typie, więc co jeśli ktoś inny definiuje inną niejawną wartość typu String? Możesz skończyć z konfliktem. Dlatego powinieneś zdefiniować swój własny specyficzny typ dla swojego własnego celu (prosty wrapper dookoła String).

Innym powodem jest to, że szukając wartości niejawnych, kompilator będzie szukać (między innymi) w obiekcie towarzyszącym (jeśli istnieje) niejawnego typu wartości. Możesz łatwo zobaczyć, jak użyteczne jest to, ponieważ obiekt towarzyszący jest naturalnym miejscem do umieszczenia domyślnej wartości domyślnej (jak w twoim przypadku). Ale jeśli niejawna wartość jest typu, którego nie jesteś właścicielem (np. String), nie możesz po prostu napisać obiektu towarzyszącego, podczas gdy z własnym typem opakowania nie ma problemu.

OK, tyle słownictwa, oto jak można to zrobić:

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, rozumiem, bardzo dziękuję :) – Loic

Powiązane problemy