在尝试回答this question时,我想出了以下代码:
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会产生以下错误:
错误:含糊不清的隐含值: 两个值StringCanBuildFrom在对象Predef中的类型=&gt; scala.collection.generic.CanBuildFrom [字符串,字符,字符串] 树型的价值客人 匹配预期类型A
我不能为我的生活看到这是怎么回事。 A必然会有IntLike
的视图范围,这是我刚刚发明的类型。 REPL确认没有可用的隐式视图:
阶&GT;隐含地[Tree =&gt; IntLike]
res14:Tree =&gt; IntLike = function1
但是
阶&GT;隐式[scala.collection.generic.CanBuildFrom [String,Char,String] =&gt; IntLike]
:18:错误:scala.collection.generic.CanBuildFrom没有隐式视图[String,Char,String] =&gt; IntLike。
那么StringCanBuildFrom
如何成为合适的类型呢?编译器是否能够解决多个依赖的implicits,如果没有,为什么会显示错误?
答案 0 :(得分: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
类型的值调用A
,而无需定义任何类型的A => A
。
您要求解析未指定类型的隐式参数以及从未指定类型到IntLike
的转换。我认为这超出了隐式分辨率算法的范围。仍然是错误信息有点奇怪。
答案 1 :(得分: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()