为什么辅助构造函数在类中看不到导入?

时间:2015-12-25 21:15:51

标签: scala constructor

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

  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):默认值       def this()= this(default.x)

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

进一步的实验表明它不仅仅是重要的。用def(甚至val)替换导入行无济于事,但错误仍然存​​在:

def default = Info.default

3 个答案:

答案 0 :(得分:3)

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

在您的示例中,问题是导入(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!
    }
 }

答案 1 :(得分:3)

由于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 :(得分:0)

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