【问题标题】:Scala Auxilliary Constructor behaviorScala 辅助构造函数行为
【发布时间】:2014-08-20 06:50:52
【问题描述】:

在 Cay Horstmann 的《不耐烦的 Scala》一书中,在第 5 章练习 8 中,有这样一个问题:

//Make a class Car with read-only properties for manufacturer, model name,
//and model year, and a read-write property for the license plate. Supply four
//  constructors. All require the manufacturer and model name. Optionally,
//model year and license plate can also be specified in the constructor. If not,
//the model year is set to -1 and the license plate to the empty string. Which
//constructor are you choosing as the primary constructor? Why?

所以我编写了这个类:

case class Car(val manufacturer: String, val modelName: String,
                 val modelYear: Int, var licensePlate : String = "") {
    def this(manufacturer: String, modelName: String, licensePlate: String) {
      this(manufacturer, modelName, -1, licensePlate)
    }

    def this(manufacturer: String, modelName: String, modelYear: Int) {

特别是这部分:

      this(manufacturer, modelName, modelYear)
    }

    def this(manufacturer: String, modelName: String) {
      this(manufacturer, modelName, -1)
    }
  }

编译器报错:

<console>:14: error: called constructor's definition must precede calling constructor's definition
             this(manufacturer, modelName, modelYear)
             ^

当我在主构造函数中将车牌的默认值作为空字符串提供时它为什么会抱怨,并且它肯定是首先定义的??

如果我这样做,错误就会消失:

this(manufacturer, modelName, modelYear, "")

或者如果我让类主构造函数没有 licensePlate 的默认值(当然在此过程中调整其他辅助构造函数调用)。

请注意,该问题专门针对 4 个构造函数,因此可以像这样调用实例创建:

new Car("Honda", "City", 2010, "ABC-123")
new Car("Honda", "City")
new Car("Honda", "City", "ABC-123")
new Car("Honda", "City", 2010)

提前感谢那些能够阐明这个问题的人。

====

感谢 Ende Neu 和 Kigyo 的回答,这看起来是完美的解决方案(删除递归构造函数):

case class Car(val manufacturer: String, val modelName: String,
               val modelYear: Int = -1, var licensePlate : String = "") {
  def this(manufacturer: String, modelName: String, licensePlate: String) {
    this(manufacturer, modelName, -1, licensePlate)
  }

  << removed constructors here >>
}

Console println new Car("Honda", "City", 2010, "ABC-123")
Console println new Car("Honda", "City")
Console println new Car("Honda", "City", "ABC-123")
Console println new Car("Honda", "City", 2010)

【问题讨论】:

  • 如果你现在在这条路上,你也可以有一个modelYear的默认值。然后你也可以删除最后一个构造函数。我以为你的想法是有四个构造函数。 :)
  • 我们是完美主义者吗,Kigyo?我再次更新了它(见上文)。现在这不是那么完美。即使我在主构造函数中有一个默认值,我仍然在辅助构造函数中将 -1 传递给模型年份。这可以进一步改进吗?
  • 在这种情况下我没有发现任何改进。 :(

标签: scala


【解决方案1】:

我只是想把一些事情说清楚。

您可以省略本示例中的最后一个参数。这里我们调用主构造函数,它有 3 个参数,只提供两个参数。 (与 Ende Neu 的例子有关)

case class Test(a: String, b: String, c: String = "test") {
  def this() = this("", "")
}

那么为什么它在您的场景中不起作用?仔细看看!

def this(manufacturer: String, modelName: String, modelYear: Int) {
  this(manufacturer, modelName, modelYear)
}

这里你也省略了最后一个参数,但是你定义的新构造函数正好接受了这个数量的参数,这使它成为一个递归调用。所以你永远不会调用主构造函数,因此你会得到错误。

在您的情况下,我还将删除默认值。也许有办法解决它,但我现在太累了。

【讨论】:

  • 我不打算在这里进行递归调用,但看起来确实如此。我被这样一个事实蒙蔽了双眼:通过这样做,我调用了带有 4 个参数的主构造函数。我想你是对的,scala 编译器应该对编译错误做出反应。我想完美的解决方案是删除这个构造函数。
  • 我错过了,对我来说可能为时已晚,确实这是正确的答案。
【解决方案2】:

您收到此错误是因为 scala 编译器无法看到您在案例类中提供的默认值,并且您正在声明一个带有三个参数而不是四个参数的构造函数,例如:

case class Test(a: String, b: String, c: String = "test") {
  def this(d: String, e: String) = this(c, e)
}

这会抛出同样的错误,你可以做的是在构造函数中指定默认值,就像你对空字符串所做的那样:

def this(d: String) = this(d, "empty")
def this(d: String, e: String) = this(d, e, "empty") // and this would return a new object

具有默认值的案例类只对应于您不必提供所有参数的构造函数,因此对于练习,您不需要两个构造函数,如果未指定年份和车牌,请使用一些预定义值,否则使用默认构造函数(已经有 4 个参数):

case class Car(val manufacturer: String, val modelName: String, val modelYear: Int, var licensePlate : String) {
  def this(manufacturer: String, modelName: String) =
    this(manufacturer, modelName, -1, "")
  }
}

然后这样称呼它:

new Car("Wolksvagen", "Polo")
Car("Ford", "Fiesta", 1984, "plate")

请注意,您必须在第一个声明中使用 new 关键字,因为它没有引用伴随对象中的 apply 方法(也可以被覆盖,请参见 SO question)。

【讨论】:

  • 您的Test 课程中有错字。应该是def this(d: String, e: String) = this(d, e)
  • 很高兴知道,书中强调的不够。但是,这个问题专门要求 4 个构造函数,所以我想我会采用删除主构造函数中的默认值的解决方案,所以我可以像这样调用实例创建(所有 4 个变体): new Car("Honda" , "City", 2010, "ABC-123") new Car("Honda", "City") new Car("Honda", "City", "ABC-123") new Car("Honda", "City ", 2010)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-28
  • 1970-01-01
  • 1970-01-01
  • 2019-01-10
  • 1970-01-01
  • 2013-10-22
相关资源
最近更新 更多