【问题标题】:How to provide default value for implicit parameters at class level如何在类级别为隐式参数提供默认值
【发布时间】:2012-09-27 20:08:05
【问题描述】:

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

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 类中定义的,例如。

【问题讨论】:

    标签: scala


    【解决方案1】:

    在隐式中使用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") 
    

    【讨论】:

      【解决方案2】:

      我找到了解决方法:

      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 解释的语法奇怪。

      【讨论】:

      • 这并不奇怪,因为隐式只会在正常参数之后插入。通常你的班级看起来像class Greetings()(implicit val ...)
      猜你喜欢
      • 1970-01-01
      • 2014-09-18
      • 1970-01-01
      • 2012-04-30
      • 1970-01-01
      • 2014-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多