4

在尝试回答这个问题时,我想出了以下代码:

    case class Monkey(bananas: Int) 
    case class Tree(rings: Int)
    case class Duck(quacks: Seq[String])

    implicit class IntLike(val x : Int) extends AnyVal

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

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

    {
        implicit val guest = Tree(50)
        purchaseCandles()
    }

请注意,这IntLike只是为了让我相信这不是关注的问题Int

这似乎是一个相当标准的隐式使用,如果不好的话,我期待它能够愉快地工作。但是,在调用purchaseCandles()REPL 时会产生以下错误:

错误:不明确的隐式值:类型 => scala.collection.generic.CanBuildFrom[String,Char,String] 的对象 Predef 中的值 StringCanBuildFrom 和 Tree 类型的值 guest 都匹配预期的类型 A

我一辈子都看不到这是怎么回事。A 必然有一个 的视图边界IntLike,这是我刚刚发明的一种类型。REPL 确认没有可用的隐式视图:

scala> 隐式[Tree => IntLike]

res14: 树 => IntLike = function1

scala> 隐式[scala.collection.generic.CanBuildFrom[String, Char, String] => IntLike]

:18: 错误:scala.collection.generic.CanBuildFrom[String,Char,String] => IntLike 没有可用的隐式视图。

那么怎么可能StringCanBuildFrom是合适的类型呢?编译器是否能够解析多个依赖隐式,如果不能,为什么会显示这个错误?

4

2 回答 2

1

在尝试回答之前,这里首先是简化的情况。请注意,您在调用purchaseCandles类型时没有任何提示A,我认为这是问题的根源。

object Foo

def test[A <% Foo.type](implicit bar: A) {}

test

错误:

<console>:10: error: ambiguous implicit values:
 both value StringCanBuildFrom in object Predef of type =>
     scala.collection.generic.CanBuildFrom[String,Char,String]
 and method conforms in object Predef of type [A]=> <:<[A,A]
 match expected type A
              test
              ^

StringCanBuildFrom似乎更像是一个令人困惑的错误消息。如果您专注于conforms这里,这不起作用的原因可能会变得更加清楚:Predef.conform声明每当您要求隐式转换A => A时,这都是通过身份来保证的。这样一来,如果您有def foo[B <% A](b: B),您始终可以foo使用 type 的值进行调用,A而无需定义任何类型的A => A.


您要求解析未指定类型的隐式参数以及从该未指定类型IntLike. 我认为这超出了隐式解析算法的范围。错误消息仍然有些奇怪。

于 2013-03-15T14:14:34.243 回答
0

仍然没有解释为什么它会失败——尽管如前所述,由于未定义的输入类型,我认为这对于隐式解析来说太过分了——但你可以让它像这样工作:

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

    implicit val guest = Tree(50)
    purchaseCandles()
于 2013-03-15T14:32:47.527 回答