假设我们有只涉及局部范围的隐式参数查找:
trait CanFoo[A] {
def foos(x: A): String
}
object Def {
implicit object ImportIntFoo extends CanFoo[Int] {
def foos(x: Int) = "ImportIntFoo:" + x.toString
}
}
object Main {
def test(): String = {
implicit object LocalIntFoo extends CanFoo[Int] {
def foos(x: Int) = "LocalIntFoo:" + x.toString
}
import Def._
foo(1)
}
def foo[A:CanFoo](x: A): String = implicitly[CanFoo[A]].foos(x)
}
在上面的代码中,
LocalIntFoo
胜过ImportedIntFoo
.有人可以解释如何使用“静态重载解决规则(§6.26.3)”来更具体地考虑它吗?
编辑 :
名称绑定(bind)优先级是一个令人信服的论点,但有几个问题尚未解决。
首先,Scala 语言引用说:
If there are several eligible arguments which match the implicit parameter’s type, a most specific one will be chosen using the rules of static overloading resolution (§6.26.3).
其次,名称绑定(bind)优先级是关于解析已知标识符
x
给特定成员pkg.A.B.x
如果有多个名为 x
的变量/方法/对象范围内。 ImportIntFoo
和 LocalIntFoo
名字不一样。第三,我可以证明单独的名称绑定(bind)优先级不起作用,如下所示:
trait CanFoo[A] {
def foos(x: A): String
}
object Def {
implicit object ImportIntFoo extends CanFoo[Int] {
def foos(x: Int) = "ImportIntFoo:" + x.toString
}
}
object Main {
def test(): String = {
implicit object LocalAnyFoo extends CanFoo[Any] {
def foos(x: Any) = "LocalAnyFoo:" + x.toString
}
// implicit object LocalIntFoo extends CanFoo[Int] {
// def foos(x: Int) = "LocalIntFoo:" + x.toString
// }
import Def._
foo(1)
}
def foo[A:CanFoo](x: A): String = implicitly[CanFoo[A]].foos(x)
}
println(Main.test)
把这个放在
test.scala
并运行 scala test.scala
,并打印出 ImportIntFoo:1
.这是因为静态重载决议(§6.26.3)说更具体的类型获胜。
如果我们假设所有符合条件的隐式值都命名相同,
LocalAnyFoo
应该屏蔽ImportIntFoo
.相关 :
这是对隐式参数解析的一个很好的总结,但它引用了 Josh 的 nescala 演示而不是规范。他的谈话是促使我研究这个问题的动力。
编译器实现
rankImplicits
最佳答案
我以博客文章的形式写了自己的答案revisiting implicits without import tax .
更新 :此外,Martin Odersky 在上述帖子中的评论显示 Scala 2.9.1 的行为为 LocalIntFoo
赢得ImportedIntFoo
实际上是一个错误。见 implicit parameter precedence again .
如果在任一阶段我们发现不止一个隐式的静态重载规则用于解决它。
更新 2 :当我向 Josh 询问有关无进口税的 Implicits 时,他向我解释说他指的是名称完全相同的implicits 的名称绑定(bind)规则。
关于Scala:隐式参数解析优先级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8623055/