辅助构造函数可以包含多个对另一个构造函数的调用,但它们的第一条语句必须是调用。
正如 Scala 中的编程 中所述,ch. 6.7:
在 Scala 中,每个辅助构造函数都必须调用另一个构造函数
与它的第一个动作相同的类。换句话说,每个语句中的第一个语句
每个 Scala 类中的辅助构造函数都将具有this(. . . ) 的形式。
调用的构造函数是主构造函数(如Rational
例如),或另一个在文本之前的辅助构造函数
调用构造函数。该规则的最终效果是每次构造函数调用
在 Scala 中,最终会调用
班级。因此,主构造函数是类的单一入口点。
如果您熟悉 Java,您可能想知道为什么 Scala 的规则
构造函数比 Java 的更严格一些。在 Java 中,构造函数
必须要么调用同一类的另一个构造函数,要么直接调用
超类的构造函数,作为它的第一个动作。在 Scala 类中,只有
主构造函数可以调用超类构造函数。增加的
Scala 中的限制实际上是一种需要付出代价的设计权衡
换取 Scala 构造函数的更简洁和简单
与 Java 相比。
就像在 Java 中一样,可以通过在主构造函数调用之前将要执行的代码提取到一个单独的方法中来绕过这个限制。在 Scala 中,它比在 Java 中更棘手,因为显然您需要将此辅助方法移动到伴随对象中,以便允许从构造函数中调用它。
此外,您的具体情况很尴尬,因为您有两个构造函数参数,并且 - 尽管可以从函数返回元组 - 然后这个返回的元组不被接受作为主构造函数的参数列表。 For ordinary functions, you can use tupled,但是唉,这似乎不适用于构造函数。一种解决方法是添加另一个辅助构造函数:
object Wibble {
private def init(baz: List[Any]): (Int, String) = {
val bazLength = baz.length
val someText = "baz length is " ++ bazLength.toString
println("init")
(bazLength, someText)
}
}
class Wibble(foo: Int, bar: String) {
println("Wibble wobble")
def this(t: (Int, String)) = {
this(t._1, t._2)
println("You can execute more code here")
}
def this(baz: List[Any]) = {
this(Wibble.init(baz))
println("You can also execute some code here")
}
}
这至少可行,即使它有点复杂。
scala> val w = new Wibble(List(1, 2, 3))
init
Wibble wobble
You can execute more code here
You can also execute some code here
w: Wibble = Wibble@b6e385
更新
正如@sschaef 在他的评论中指出的那样,这可以使用伴随对象中的工厂方法来简化:
object Wobble {
def apply(baz: List[Any]): Wobble = {
val bazLength = baz.length
val someText = "baz length is " ++ bazLength.toString
println("init")
new Wobble(bazLength, someText)
}
}
class Wobble(foo: Int, bar: String) {
println("Wobble wibble")
}
因此我们不再需要new 来创建对象:
scala> val w = Wobble(List(1, 2, 3))
init
Wobble wibble
w: Wobble = Wobble@47c130