假设我们只有局部范围的隐式参数查找:
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)
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,LocalIntFoo胜过ImportedIntFoo.有人可以使用"静态重载决策规则(§6.26.3)"来解释它是如何被认为更具体的吗?
编辑:
名称绑定优先级是一个引人注目的参数,但有几个问题尚未解决.首先,Scala语言参考说:
如果有几个符合条件的参数与隐式参数的类型匹配,则将使用静态重载决策的规则(第6.26.3节)选择最具体的参数.
其次,名称绑定优先级是关于在范围内有多个变量/方法/对象的情况下解析x特定成员的已知标识符.并且没有相同的名称.pkg.A.B.xxImportIntFooLocalIntFoo
第三,我可以证明单独的名称绑定优先级不起作用如下:
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)
Run Code Online (Sandbox Code Playgroud)
把它放入test.scala并运行scala test.scala,然后打印出来ImportIntFoo:1.这是因为静态重载决策(第6.26.3节)表示更具体的类型获胜.如果我们假装所有符合条件的隐式值都被命名为相同,则LocalAnyFoo应该进行掩码ImportIntFoo.
相关:
这是隐式参数解析的一个很好的总结,但它引用了Josh的nescala表示而不是规范.他的演讲是我调查这一点的动机.
编译器实现
Eug*_*ota 16
我以博客文章的形式写了我自己的答案,重新审视了没有进口税的含义.
更新:此外,Martin Odersky在上述帖子中的评论显示,Scala 2.9.1的LocalIntFoo获胜行为ImportedIntFoo实际上是一个错误.请再次参见隐式参数优先级.
如果在任一阶段我们发现多个隐式,则使用静态重载规则来解决它.
更新2:当我向Josh询问没有进口税的Implicits时,他向我解释说他指的是名称绑定规则的名称完全相同的implicits.
来自http://www.scala-lang.org/docu/files/ScalaReference.pdf,第2章:
Scala中的名称标识统称为实体的类型,值,方法和类.名称由本地定义和声明(§4),继承(§5.1.3),import子句(§4.7)或package子句(§9.2)引入,它们统称为绑定.
不同类型的绑定优先于它们定义:1.定义和声明是本地的,继承的或由发生定义的同一编译单元中的package子句提供的具有最高优先级的定义和声明.2.明确的进口具有次高的优先权.3.通配符导入的优先级次高.4.包装条款提供的定义不在发生定义的编译单元中具有最低优先级.
我可能弄错了,但是对foo(1)的调用与LocalIntFoo在同一个编译单元中,导致该转换优先于ImportedIntFoo.
| 归档时间: |
|
| 查看次数: |
8904 次 |
| 最近记录: |