如何在类级别为隐式参数提供默认值

时间:2012-10-07 07:53:21

标签: scala

我正在尝试使用一些隐含参数的方法定义一个类:

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

我从另一个班级

使用这个班级
implicit val greetings = "hello"                //> greetings  : java.lang.String = hello
Greetings.say("loic")                           //> res0: String = hello loic
Greetings.say("loic")("hi")                     //> res1: String = hi loic

我的问题是它只有在我的Greetings对象之外定义隐式val时才有效。 我希望能够提供带有隐式参数的方法,在我的类中使用默认值,以便更容易地使用我的API(如Scala集合API)。

所以我想这样做,但它不起作用(未找到隐含值):

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

然后

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

我知道我可以使用(implicit greetings: String = "hello")定义默认值,但我想在课程级别进行,以避免在有很多方法时重复。

我想我错过了一些东西,因为我看到CanBuildFrom类中定义了List,例如。

2 个答案:

答案 0 :(得分:26)

在隐式中使用String这样的通用类型是个坏主意。 主要原因是隐式查找完全基于类型,那么如果其他人定义String类型的另一个隐式值呢?你可能最终会发生冲突。因此,您应该为自己的目的定义自己的特定类型(String的简单包装)。

另一个原因是,在查找隐式值时,编译器会将(以及其他位置)查找到隐式值类型的伴随对象(如果有)。您可以很容易地看到它的用处,因为伴随对象是放置默认隐式值的自然位置(如您的情况)。但是如果隐式值是你不拥有的类型(例如String),你就不能为它编写一个伴随对象,而使用你自己的包装类型则没有问题。

好的,足够的措辞,以下是你可以做到的:

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

答案 1 :(得分:7)

我找到了解决方法:

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

像这样,我可以有一个默认值,如果我想要覆盖它:

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

注意:new Greetings()("coucou")正在运行,而不是new Greetings("coucou"),因为here解释了语法异常。