作为我的其他question的后续内容,请参阅代码中的评论/问题:
case class Implicit(name: String)
def foo(implicit i: Implicit = null) = println(Option(i))
def bar1(implicit i: Implicit) {
foo // prints None
implicit val i = Implicit("J") // Why is call to foo above affected although this line comes after?
foo // prints Some(Implicit(I))
}
def bar2(implicit i: Implicit) {
foo // prints None
implicit val i = null
implicit val j = Implicit("J")
foo // prints None // Why? Should raise ambiguous implicits or at least choose j.
}
def bar3(implicit i: Implicit) {
foo // prints None
val i = null
implicit val j = Implicit("J")
foo // prints Some(Implicit(J)) // Now it works as I expected to work in bar2.
}
def bar4(implicit i: Implicit) { // That's how I expected to see bar1 working. A ugly hack here.
foo // prints Some(Implicit(I))
locally {
val i = null
implicit val j = Implicit("J")
foo // prints Some(Implicit(J))
}
}
val i = Implicit("I")
bar1(i)
bar2(i)
bar3(i)
bar4(i)
答案 0 :(得分:5)
您的代码遭受名称遮蔽。 chapter 2中的规范说明了这一点:
绑定具有一个范围,在该范围内,可以使用简单名称访问由单个名称定义的实体。范围是嵌套的。 在某个内部范围内的绑定会影响同一范围内较低优先级的绑定以及外部作用域中相同或较低优先级的绑定。
在您的示例中,这意味着使用
def foo(implicit i: Implicit) = println(Option(i))
我们有以下可能性:
隐式参数i
会传递给foo
,因为x
是前向引用:
scala> def f(implicit i: Implicit) = {foo; implicit val x = Implicit("i")}
f: (implicit i: Implicit)Unit
没有任何内容可以传递给foo
,因为参数i
被本地值i
遮蔽,后者具有更高的优先级,但无法调用,因为它是一个前瞻性参考。
scala> def f(implicit i: Implicit) = {foo; implicit val i = Implicit("i")}
<console>:11: error: could not find implicit value for parameter i: Implicit
def f(implicit i: Implicit) = {foo; implicit val i = Implicit("i")}
^
当值具有相同名称时会被遮蔽,但它不能具有相同的类型:
scala> def f(implicit i: Implicit) = {implicit val j = Implicit("i"); foo}
<console>:11: error: ambiguous implicit values:
both value i of type Implicit
and value j of type Implicit
match expected type Implicit
def f(implicit i: Implicit) = {implicit val j = Implicit("i"); foo}
^
scala> def f(implicit i: Implicit) = {val i = null; implicit val j = Implicit("i"); foo}
f: (implicit i: Implicit)Unit
范围内存在多个含义,但其中一个具有更高的优先级。在这种情况下,i
具有更高的优先级,因为Null <: Implicit
scala> def f(implicit i: Implicit) = {implicit val i = null; implicit val j = Implicit("i"); foo}
f: (implicit i: Implicit)Unit
您使用隐式参数的默认值声明了foo
的定义。这并没有改变上述规则,但是当没有其他值可用时,编译器可以选择默认值。