下面的代码给出了编译错误:
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
答案 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
方法的伴随对象。