scala - 为什么 Scala 中的辅助构造函数只能由对另一个构造函数的一次调用组成?

标签 scala

我认为我看到了定义辅助构造函数的优点,主构造函数是类的唯一入口点。但是为什么我不能做这样的事情呢?

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)
  }
}

这可能是一种保证辅助构造函数没有副作用和/或不能提前返回的方法吗?

最佳答案

辅助构造函数可以包含多个对另一个构造函数的调用,但它们的第一条语句必须是调用。

正如在 Scala 编程中解释的那样,ch。 6.7:

In Scala, every auxiliary constructor must invoke another constructor of the same class as its first action. In other words, the first statement in every auxiliary constructor in every Scala class will have the form this(. . . ). The invoked constructor is either the primary constructor (as in the Rational example), or another auxiliary constructor that comes textually before the calling constructor. The net effect of this rule is that every constructor invocation in Scala will end up eventually calling the primary constructor of the class. The primary constructor is thus the single point of entry of a class.

If you’re familiar with Java, you may wonder why Scala’s rules for constructors are a bit more restrictive than Java’s. In Java, a constructor must either invoke another constructor of the same class, or directly invoke a constructor of the superclass, as its first action. In a Scala class, only the primary constructor can invoke a superclass constructor. The increased restriction in Scala is really a design trade-off that needed to be paid in exchange for the greater conciseness and simplicity of Scala’s constructors compared to Java’s.



就像在 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

关于scala - 为什么 Scala 中的辅助构造函数只能由对另一个构造函数的一次调用组成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14207989/

相关文章:

Scala 在案例类中使用 Wea​​kReference

Scala:没有明确已知类型参数的类型转换

scala - 将笛卡尔坐标组分组到apache Spark中的单元格

scala - 使用 for/yield 从序列中删除元素

scala - "does not take parameters"链接方法调用时没有句点

scala - 使用 shadowJar 和 Scala 依赖项时如何修复丢失的 conf 文件?

java - Scala 的类和对象的问题

java - Java 或 Scala 中是否有用于时间间隔组合的库?

scala - Scala:为什么可以将Int转换为Unit?

java - Scala 2.8.1 隐式转换为 java.util.List<java.util.Map<String, Object>>