我认为我看到了以这样一种方式定义辅助构造函数的优点,即主构造函数是类的单独入口点。但为什么我不能这样做呢?
class Wibble(foo: Int, bar: String) {
def this(baz: List[Any]) = {
val bazLength = baz.length
val someText = "baz length is " ++ bazLength.toString
this(bazLength, someText)
}
}
这可能是一种保证辅助构造函数没有副作用和/或不能提前返回的方法吗?
答案 0 :(得分:18)
辅助构造函数可以包含多个另一个构造函数的调用,但它们的第一个语句必须是所谓的调用。
如 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