Scope of implicits

纵然是瞬间 提交于 2019-12-11 02:43:25

问题


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:

  1. The implicit param i gets passed to foo because x would be a forward reference:

    scala> def f(implicit i: Implicit) = {foo; implicit val x = Implicit("i")}
    f: (implicit i: Implicit)Unit
    
  2. 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")}
                                          ^
    
  3. 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
    
  4. 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
    

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!