我想在case类构造函数中声明一些辅助值,但似乎Scala不正确。
简而言之,以下代码是正确的:
case class Something(
text1: String,
text2: String
) {
def this(datetime: LocalDateTime) {
this(
s"date: ${datetime.toLocalDate.toString()}",
s"time: ${datetime.toLocalTime.toString()}"
)
}
}
以下不是:
case class Something(
text1: String,
text2: String
) {
def this(datetime: LocalDateTime) {
val date = datetime.toLocalDate.toString()
val time = datetime.toLocalTime.toString()
this(
s"date: $date",
s"time: $time"
)
}
}
即使后者更易读,也更容易维护。 (想象一下,使用比调用两种方法更复杂的操作。)为什么会这样?
有没有其他方法来编写这样的构造函数或解决此问题的方法?
答案 0 :(得分:2)
在Scala中,第一次调用必须是主构造函数。之后,您可以拥有任意数量的代码。请阅读this以获取解释。
类似的规则适用于Java和super。虽然不完全相同。阅读this。
this和super必须首先的原因是,在调用实际的this(x,y)之前,可以将字段设置为各种值。这意味着正在构造对象,并且在构造正在进行时,任何可能引用该对象的线程都可以看到不同的值。
感谢。
答案 1 :(得分:0)
辅助构造函数有一个约束,它应该在其主体的第一行调用前一个辅助构造函数或主构造函数。第二个代码不遵循该规则。因此错误。
答案 2 :(得分:0)
在第二种情况下,不允许在this(params)
调用之前在构造函数中定义变量,如computing inside constructors are discouraged in scala class or case class。 解决这个问题的一种方法是传递内联构造函数参数。
test("test case class custom constructor") {
case class Something(text1: String,text2: String) {
def this(datetime: LocalDateTime) {
this(datetime.toLocalDate.toString(), datetime.toLocalTime.toString())
//you can do whatever you want after this(x, y) is invoked
val testVal = "apple"
println(testVal)
}
}
new Something(LocalDateTime.now()).text1 shouldBe "2017-07-16"
new Something(LocalDateTime.now()).text2 should not be empty
}
另一种方式(Encouraged way)定义案例类,然后在随播对象中定义apply
,如下所示( for old版本可能2.11.8
,必须首先定义伴侣对象,并且只有现在似乎已修复的案例类 - https://issues.scala-lang.org/browse/SI-3772)
test("test class with companion apply method") {
case class Something(val text1: String, val text2: String) {}
object Something {
def apply(datetime: LocalDateTime): Something = {
val x = datetime.toLocalDate.toString()
val y = datetime.toLocalTime.toString()
new Something(x, y)
}
}
Something(LocalDateTime.now()).text1 shouldBe "2017-07-16"
Something(LocalDateTime.now()).text2 should not be empty
}
scastie code - https://scastie.scala-lang.org/prayagupd/yn2bJWHkQ6Gbli5Ll6I6CQ/1