2012-10-07 12 views
17

sto cercando di definire una classe con alcuni metodi di prendere un parametro implicito:Come fornire valore di default per i parametri impliciti a livello di classe

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

Io uso questa classe da un'altra classe

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

Il mio problema è che funziona solo se definisco il valore implicito al di fuori dell'oggetto Greetings. Mi piacerebbe essere in grado di fornire metodi con parametri impliciti, con un valore predefinito all'interno della mia classe, per rendere più facile l'uso della mia API (come l'API di raccolta Scala).

Così mi piacerebbe fare questo, ma non sta funzionando (valore implicito non trovato):

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

e poi

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

so di poter definire un valore predefinito con (implicit greetings: String = "hello") ma Mi piacerebbe farlo a livello di classe, per evitare di ripetere se ci sono molti metodi.

Immagino di perdere qualcosa perché ho visto che CanBuildFrom è definito all'interno della classe List, ad esempio.

risposta

6

ho trovato una soluzione:

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

come non posso avere un valore predefinito ed eseguire l'override se voglio:

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 

Nota: new Greetings()("coucou") funziona, non new Greetings("coucou"), perché di una sintassi di stranezza spiegato here.

+0

Non è strano, in quanto implicita sarà inserito secondo solo ai parametri normali. Normalmente la tua classe sarebbe simile a 'class Greetings() (implicito val ...)' – thatsIch

24

È una cattiva idea utilizzare un tipo generico come String in modo implicito. Il motivo principale è che la ricerca implicita è basata esclusivamente sul tipo, quindi cosa succede se qualcun altro definisce un altro valore implicito di tipo String? Potresti finire con un conflitto. Quindi dovresti definire il tuo tipo specifico per il tuo scopo (un semplice wrapper attorno a String).

Un'altra ragione è che quando si cercano valori impliciti, il compilatore cercherà (tra l'altro) nell'oggetto associato (se presente) del tipo di valore implicito. Puoi facilmente vedere quanto è utile, dato che l'oggetto associato è il luogo naturale in cui inserire un valore implicito predefinito (come nel tuo caso). Ma se il valore implicito è di un tipo che non possiedi (come String) non puoi scrivere un oggetto companion per esso, mentre con il tuo tipo di wrapper non ci sono problemi.

Ok, basta verbosità, ecco come si può fare:

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 ho capito, molte grazie :) – Loic

Problemi correlati