2012-10-07 16 views
17

Estoy tratando de definir una clase con algunos métodos de tomar un parámetro implícito:Cómo proporcionar un valor por defecto para los parámetros implícitos a nivel de clase

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

utilizo esta clase de otra clase

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

Mi problema es que solo funciona si defino el valor implícito fuera de mi objeto Saludos. Me gustaría poder proporcionar métodos con parámetros implícitos, con un valor predeterminado dentro de mi clase, para facilitar el uso de mi API (como la API de la colección Scala).

Así que me gustaría hacer esto, pero no está funcionando (valor implícito no encontrado):

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

y luego

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

Sé que puedo definir un valor predeterminado con (implicit greetings: String = "hello") pero Me gustaría hacerlo a nivel de clase, para evitar repetir si hay muchos métodos.

Supongo que me falta algo porque vi que CanBuildFrom se define dentro de la clase List, por ejemplo.

Respuesta

6

he encontrado una solución:

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

como no puedo tener un valor por defecto y anularlo si quiero:

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") está trabajando, no new Greetings("coucou"), porque de una sintaxis extraña explicada here.

+0

No es extraño, ya implícita sólo se inserta en segundo lugar a los parámetros normales. Normalmente su clase se vería como 'clase Greetings() (val implícito ...)' – thatsIch

24

No es buena idea usar un tipo general como String de forma implícita. La razón principal es que la búsqueda implícita se basa únicamente en el tipo, entonces, ¿qué pasa si alguien más define otro valor implícito de tipo Cadena? Puede terminar con un conflicto. Por lo tanto, debe definir su propio tipo específico para su propio propósito (un simple contenedor alrededor de String).

Otra razón es que al buscar valores implícitos, el compilador buscará (entre otros lugares) en el objeto complementario (si lo hay) del tipo de valor implícito. Puede ver fácilmente lo útil que es, ya que el objeto complementario es el lugar natural para poner un valor implícito predeterminado (como en su caso). Pero si el valor implícito es de un tipo que no es de su propiedad (como String), no puede escribir un objeto complementario para él, mientras que con su propio tipo de envoltorio no hay problema.

OK, suficiente verborrea, aquí es cómo puede hacerlo:

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, lo entiendo, muchas gracias :) – Loic

Cuestiones relacionadas