【问题标题】:Why does auxiliary constructor not see import done in the class?为什么辅助构造函数看不到类中的导入?
【发布时间】:2015-12-25 21:15:51
【问题描述】:

下面的代码给出了编译错误:

  class Info(val x: String)

  object Info {
    val default = new Info("top")
  }

  case class Data(x: String) {
    import Info.default

    def this() = this(default.x)

  }

错误:(11, 23) not found: value default def this() = this(default.x)

为什么在构造函数中没有看到符号default,尽管导入了?

进一步的实验表明它不仅仅是进口。用def(甚至val)替换导入行没有帮助,错误仍然存​​在:

def default = Info.default

【问题讨论】:

  • 嗯,我以为我知道答案,但似乎我不太对。

标签: scala constructor


【解决方案1】:

由于the scoping of self constructor invocations(当辅助构造函数调用主构造函数时),作用域无法按您预期的方式工作:

构造函数的签名和自构造函数调用 定义在范围内进行类型检查和评估 在封闭类定义处的效果,由 封闭类的任何类型参数以及任何早期的 封闭模板的定义。

换句话说,表达式default.x 的有效范围是Data 之外的范围。

这很令人困惑,因为从文本上看,该表达式似乎在类中。

此规则与词法范围有关,与评估顺序无关。

您必须将导入移到类定义之外。

为了好玩,在以下情况下,范围界定略有破坏:

object Playroom {
  def default = "playing"
  case class Toy(squeezeMsg: String = default)
  object Toy {
    def default = "srsly"
  }
}

object Test extends App {
  import Playroom._
  println(Toy())
  println(new Toy())
}

这是this puzzler。一般来说,在同伴上使用apply 方法会更惯用(也更健壮)。

【讨论】:

    【解决方案2】:

    这是根据规范进行的。类的主体是所谓的主构造函数的一部分。 辅助构造函数需要通过调用之前定义的主构造函数或其他辅助构造函数开始。假设您只有一个辅助,因为对主的调用必须是辅助中的第一个语句,这意味着在第一个语句期间,您无权访问主中定义的任何内容。第一次调用完成后,您就可以访问主数据库中定义的任何成员和导入。

    在您的示例中,问题是导入 (import Info.default) 对您的辅助的第一条语句不可见。如果你用def this() = this(Info.default.x) 替换它,它应该可以工作。

    示例:

    以下编译正常,因为对Constant 的调用是在调用主之后完成的。

    class G(i: Int) {
       val Constant = 1
       // No argument auxiliary constructor    
       def this() = {
          this(3) // Call to primary 
          println(Constant * 2)
       }
    }
    

    由于对 Constant 的调用是在调用主节点之前完成的,因此以下内容无法编译,这意味着尚未创建 Constant

    class G(i: Int) {
       val Constant = 1
       // No argument auxiliary constructor    
       def this() = {
          this(Constant) // This will cause an error!
       }
    }
    

    解决方案:

    在伴生对象中定义您需要的任何常量。根据定义,伴生对象首先被初始化,因此您将能够从类的构造函数中访问它的任何成员。

    object G {
       val Constant = 1
    }
    
    class G(i: Int) {
        // No argument auxiliary constructor    
        def this() = {
           this(G.Constant) // This now works!
        }
     }
    

    【讨论】:

    • Have any imports in the companion 实际上没有帮助。
    【解决方案3】:

    在 Scala 中,在调用主构造函数之前,类中定义的任何字段都不可用。要修复它,通常使用带有apply 方法的伴生对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-28
      • 2014-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多