【问题标题】:Can an implicit conversion of an implicit value satisfy an implicit parameter?隐式值的隐式转换能否满足隐式参数?
【发布时间】:2014-12-12 07:26:47
【问题描述】:

我正在定义一些 Scala 隐式函数,以便更轻松地处理一组特定的、不可更改的 Java 类。以下 Scala 代码是一个简化的示例,显然看起来很疯狂,在现实世界中,我试图从 Monkey、Tree 和 Duck 中隐式获取特定资源(而不是数字年龄),以用于各种方法,例如 purchaseCandles():

// actually 3 Java classes I can not change:
case class Monkey(bananas: Int) 
case class Tree(rings: Int)
case class Duck(quacks: Seq[String])

// implicits I created to make my life easier...
implicit def monkey2Age(monkey: Monkey): Int = monkey.bananas / 1000
implicit def tree2Age(tree: Tree): Int = tree.rings
implicit def duck2Age(duck: Duck): Int = duck.quacks.size / 100000

// one of several helper methods that I would like to define only once,
// only useful if they can use an implicit parameter.
def purchaseCandles()(implicit age: Int) = {
  println(s"I'm going to buy $age candles!")
}

// examples of usage
{
  implicit val guest = Monkey(10000)

  purchaseCandles()
}

{
  implicit val guest = Tree(50)

  purchaseCandles()
}

{
  implicit val guest = Duck(Seq("quack", "quack", "quack"))

  purchaseCandles()
}

编译器错误,出现3次:

could not find implicit value for parameter age: Int 
purchaseCandles()
               ^

抛开这个示例代码疯狂的许多不同方式,我真正的问题是:隐式值的隐式转换能否满足 Scala 中的隐式参数?

【问题讨论】:

    标签: scala implicit-conversion implicit-parameters


    【解决方案1】:

    简短的回答:不。 Scala 的编译器只会应用单个隐式,因此如果它未能发现周围的implicit int,它将停止并放弃。

    但是,您可以编写 purchaseCandles 方法来操作可以转换为 Int 的类型,并且需要该类型的参数:

    def purchaseCandles[A <% Int]()(implicit age : A) = {
      val asAge : Int = age
      println(s"I'm going to buy $asAge candles!")
    }
    

    asAge 部分是强制应用隐式转换所必需的。

    到目前为止,在这种情况下,我似乎需要指定 A 的类型,尽管我不知道为什么:因为不应该有其他类型的值可以隐式转换为 @ 987654328@(这也发生在全新的类型上,所以它不是Int 的普遍存在。)但是你可以这样做:

    {
      implicit val guest = Monkey(10000)
    
      purchaseCandles[Monkey]()
    }
    

    然而,这种隐式的使用可能是个坏主意!

    【讨论】:

    • 感谢您的精彩解释 - 不得不指定 A tho 的类型感到羞耻。
    • View bounds [A &lt;% Int] 在这个答案中使用现在已被弃用,更多信息在这里:github.com/scala/scala/pull/2909
    【解决方案2】:

    您实际上可以这样做:您只需将隐式转换的参数也标记为隐式:

    implicit def monkey2Age(implicit monkey: Monkey): Int = monkey.bananas / 1000
    implicit def tree2Age(implicit tree: Tree): Int = tree.rings
    implicit def duck2Age(implicit duck: Duck): Int = duck.quacks.size / 100000
    

    这将按照你想要的方式链接它们。

    与往常一样:请注意,它也会在您不希望它出现的地方这样做。顺便说一句,我强烈建议不要使用 Int 类型的隐式参数(或其隐式值)。它太笼统了。 (我有点假设这就像你的例子一样)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-09
      • 1970-01-01
      相关资源
      最近更新 更多