问题
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)
回答1:
Your code suffers from name shadowing. The spec in chapter 2 says about this:
A binding has a scope in which the entity defined by a single name can be accessed using a simple name. Scopes are nested. A binding in some inner scope shadows bindings of lower precedence in the same scope as well as bindings of the same or lower precedence in outer scopes.
In your example, this means that with
def foo(implicit i: Implicit) = println(Option(i))
we have the following possibilities:
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
Nothing can be passed to
foo
because parameteri
is shadowed by the local valuei
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
There exists multiple implicits in scope, but one has higher precedence. In this case
i
has the higher precedence becauseNull <: Implicit
scala> def f(implicit i: Implicit) = {implicit val i = null; implicit val j = Implicit("i"); foo} f: (implicit i: Implicit)Unit
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.
来源:https://stackoverflow.com/questions/25096097/scope-of-implicits