隐式范围 [英] Scope of implicits

查看:86
本文介绍了隐式范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为我其他问题的后续措施,请参见代码中的注释/问题:

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))

我们有以下可能性:

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

  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

  • 什么都不能传递给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屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆