scala - 隐式的范围

标签 scala scope implicit

作为我的另一个 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)

最佳答案

您的代码受到名称隐藏的影响。 chapter 2中的规范对此说道:

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.

在您的示例中,这意味着

def foo(implicit i: Implicit) = println(Option(i))

我们有以下可能性:

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

    scala> def f(implicit i: Implicit) = {foo; implicit val x = Implicit("i")}
    f: (implicit i: Implicit)Unit
    
  2. 没有任何内容可以传递给 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")}
                                          ^
    
  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
    
  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
    

您对 foo 的定义声明了隐式参数的默认值。这不会改变上述规则,但编译器可以在没有其他值可用时选择默认值。

关于scala - 隐式的范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25096097/

相关文章:

scala - Scala 是否智能地终止计算折叠操作的 OR 表达式?

json - 如何配置 Circe 以停止使用嵌套类名作为编码 JSON 中的键名?

audio - Phaser的示波器问题-使用声音

c++ - 可能的继承范围问题 :

c - 当外部变量不是全局变量时发现阴影变量

scala - Scalala 是否提供了将向量插入矩阵的直接方法?

scala - Spark : NullPointerException when RDD isn't collected before map

Scala:具有相同声明的两个隐式参数

java - 如何在 Java 中从 Scala 传递通过包对象定义的隐式 val

C++,隐式转换/构造函数是如何确定的?