[英]Scala resolution of multiple implicit parameters
In trying to answer this question , I came up with the following code: 在试图回答这个问题时 ,我想出了以下代码:
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()
}
Note that the IntLike
is only there to convince me this wasn't a problem focussed on Int
. 请注意, IntLike
只是为了让我相信这不是一个专注于Int
的问题。
This seems a fairly standard, if bad, use of implicits, and I was expecting it to work happily. 这似乎是一个相当标准,如果不好,使用implicits,我期待它愉快地工作。 However, on invoking purchaseCandles()
the REPL yields the following error: 但是,在调用purchaseCandles()
,REPL会产生以下错误:
error: ambiguous implicit values: both value StringCanBuildFrom in object Predef of type => scala.collection.generic.CanBuildFrom[String,Char,String] and value guest of type Tree match expected type A 错误:模糊隐含值:两个值StringCanBuildFrom在对象Predef中的类型=> scala.collection.generic.CanBuildFrom [String,Char,String]和值类型为guest的类型匹配预期类型A
I cannot for the life of me see how this is the case. 我不能为我的生活看到这是怎么回事。 A is bound to have an view bound of IntLike
, a type I just invented. A必然会有一个IntLike
的视图边界, IntLike
是我刚刚发明的一种类型。 The REPL confirms that there is no implicit view available: REPL确认没有可用的隐式视图:
scala> implicitly[Tree => IntLike] scala>隐式[Tree => IntLike]
res14: Tree => IntLike = function1 res14:Tree => IntLike = function1
but 但
scala> implicitly[scala.collection.generic.CanBuildFrom[String, Char, String] => IntLike] scala> implicitly [scala.collection.generic.CanBuildFrom [String,Char,String] => IntLike]
:18: error: No implicit view available from scala.collection.generic.CanBuildFrom[String,Char,String] => IntLike. :18:错误:scala.collection.generic.CanBuildFrom [String,Char,String] => IntLike没有隐式视图。
So how can StringCanBuildFrom
be of an appropriate type? 那么StringCanBuildFrom
如何成为合适的类型呢? Is the compiler capable of resolving the multiple dependent implicits, and if not, why is this the error being shown? 编译器是否能够解析多个依赖的implicits,如果没有,为什么会显示错误?
Before attempting an answer, here is first the reduced case. 在尝试回答之前,首先是减少的案例。 Note that you are calling purchaseCandles
with no hint whatsoever on type A
which I think is the origin of the problem. 请注意,您正在调用purchaseCandles
而没有任何关于类型A
提示,我认为这是问题的根源。
object Foo
def test[A <% Foo.type](implicit bar: A) {}
test
Error: 错误:
<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
^
The StringCanBuildFrom
seems more like a confusing error message. StringCanBuildFrom
看起来更像一个令人困惑的错误消息。 If you concentrate on conforms
here, the reason why this doesn't work might become more clear: Predef.conform
states that whenever you ask for an implicit conversion A => A
, this is guaranteed by means of identity. 如果您专注于conforms
这里,为什么这不工作可能会变得更加清晰的理由: Predef.conform
指出,每当你问的隐式转换A => A
,这是由身份来保证。 This is so that if you have def foo[B <% A](b: B)
, you can always call foo
with a value of type A
without the need to define any sort of A => A
. 这样,如果你有def foo[B <% A](b: B)
,你总是可以用类型A
的值调用foo
,而不需要定义任何类型的A => A
You are asking for the resolution of implicit argument of an unspecified type along with a conversion from that unspecified type to IntLike
. 您要求解析未指定类型的隐式参数以及从未指定类型到IntLike
的转换。 I think that is beyond the scope of the implicit resolution algorithm. 我认为这超出了隐式分辨率算法的范围。 Still the error message is somewhat strange. 仍然错误消息有点奇怪。
Still no explanation why it fails—although, as said, I expect this is too much for the implicit resolution because of the undefined input type—, but you can make it work like this: 仍然没有解释为什么它失败 - 尽管如上所述,我认为由于未定义的输入类型,这对于隐式解析来说太多了,但是你可以让它像这样工作:
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()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.