隐含范围

Pet*_*itz 2 scope scala implicit

作为我的其他问题的后续内容,请参阅代码中的注释/问题:

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)
Run Code Online (Sandbox Code Playgroud)

kir*_*uku 5

您的代码遭受名称阴影.第2章中的规范说明了这一点:

绑定具有一个范围,在该范围内,可以使用简单名称访问由单个名称定义的实体.范围是嵌套的.某些内部作用域中的绑定会影响同一作用域中较低优先级的绑定以及外部作用域中相同或较低优先级的绑定.

在您的示例中,这意味着

def foo(implicit i: Implicit) = println(Option(i))
Run Code Online (Sandbox Code Playgroud)

我们有以下可能性:

  1. 隐式参数i传递给foo因为x是一个前向引用:

    scala> def f(implicit i: Implicit) = {foo; implicit val x = Implicit("i")}
    f: (implicit i: Implicit)Unit
    
    Run Code Online (Sandbox Code Playgroud)
  2. 无法传递任何内容,foo因为参数ii具有更高优先级的本地值遮蔽,但由于它是前向引用而无法调用.

    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")}
                                          ^
    
    Run Code Online (Sandbox Code Playgroud)
  3. 值具有相同名称时会被遮蔽,但它不能具有相同的类型:

    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
    
    Run Code Online (Sandbox Code Playgroud)
  4. 范围内存在多个含义,但其中一个具有更高的优先级.在这种情况下i具有更高的优先级,因为Null <: Implicit

    scala> def f(implicit i: Implicit) = {implicit val i = null; implicit val j = Implicit("i"); foo}
    f: (implicit i: Implicit)Unit
    
    Run Code Online (Sandbox Code Playgroud)

您的定义foo是使用隐式参数的默认值声明的.这不会改变上述规则的任何内容,但是当没有其他值可用时,编译器可以选择默认值.