隐式范围 [英] Scope of implicits
问题描述
作为我其他问题的后续措施,请参见代码中的注释/问题:
As a follow up to my other question, see comments / questions in code:
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)
推荐答案
您的代码遭受名称屏蔽. 第2章对此说:
Your code suffers from name shadowing. The spec in chapter 2 says about this:
绑定具有一个范围,在该范围内可以使用简单名称访问由单个名称定义的实体.范围是嵌套的. 某些内部作用域中的绑定会掩盖同一作用域中较低优先级的绑定,以及外部作用域中具有相同或较低优先级的绑定.
在您的示例中,这意味着使用
In your example, this means that with
def foo(implicit i: Implicit) = println(Option(i))
我们有以下可能性:
-
隐式参数
i
传递给foo
,因为x
将是前向引用:
The implicit param
i
gets passed tofoo
becausex
would be a forward reference:
scala> def f(implicit i: Implicit) = {foo; implicit val x = Implicit("i")}
f: (implicit i: Implicit)Unit
什么都不能传递给foo
,因为参数i
被优先级较高的局部值i
遮盖,但由于它是前向引用而无法调用.
Nothing can be passed to foo
because parameter i
is shadowed by the local value i
which has higher precedence but can't be called because it is a forward reference.
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")}
^
具有相同名称的值,但不能具有相同类型的值会被遮盖:
A value is shadowed when it has the same name, but it must not have the same type:
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
There exists multiple implicits in scope, but one has higher precedence. In this case i
has the higher precedence because Null <: Implicit
scala> def f(implicit i: Implicit) = {implicit val i = null; implicit val j = Implicit("i"); foo}
f: (implicit i: Implicit)Unit
您对foo
的定义已声明为隐式参数的默认值.上面提到的规则并没有改变任何东西,但是当没有其他值可用时,编译器可以选择默认值.
Your definition of foo
was declared with a default value for the implicit parameter. This doesn't change anything at the rules mentioned above, but the compiler can choose the default value when no other value is available.
这篇关于隐式范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!