Scala:为什么我不能在构造函数中声明值?
Scala: why can't I declare values in a constructor?
我想在 case class 构造函数中声明一些辅助值,但 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"
)
}
}
尽管后者会更易读且更易于维护。 (想象一下使用比调用两个方法更复杂的操作。)这是为什么?
是否有另一种方法来编写这样的构造函数或解决此问题的方法?
辅助构造函数有一个约束,它应该在其主体的第一行调用先前的辅助构造函数或主构造函数。第二个代码不遵循该规则。因此错误。
在第二种情况下,您不允许在 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) is define case class and then define apply
inside a companion object as below (for older version maybe 2.11.8
, companion object had to be defined first and only case class which seems to be fixed now - 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 代码 - https://scastie.scala-lang.org/prayagupd/yn2bJWHkQ6Gbli5Ll6I6CQ/1
在 Scala 中,第一次调用必须是主构造函数。之后,您可以拥有任意多的代码。阅读 this 以获得解释。
类似的规则适用于 Java 和 super。虽然不完全一样。阅读this。
this 和 super 必须放在第一个的原因是,可以在调用实际的 this(x, y) 之前将字段设置为各种值。这意味着正在构造对象,并且在构造过程中可能引用该对象的任何线程都可以看到不同的值。
谢谢。
我想在 case class 构造函数中声明一些辅助值,但 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"
)
}
}
尽管后者会更易读且更易于维护。 (想象一下使用比调用两个方法更复杂的操作。)这是为什么?
是否有另一种方法来编写这样的构造函数或解决此问题的方法?
辅助构造函数有一个约束,它应该在其主体的第一行调用先前的辅助构造函数或主构造函数。第二个代码不遵循该规则。因此错误。
在第二种情况下,您不允许在 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) is define case class and then define apply
inside a companion object as below (for older version maybe 2.11.8
, companion object had to be defined first and only case class which seems to be fixed now - 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 代码 - https://scastie.scala-lang.org/prayagupd/yn2bJWHkQ6Gbli5Ll6I6CQ/1
在 Scala 中,第一次调用必须是主构造函数。之后,您可以拥有任意多的代码。阅读 this 以获得解释。
类似的规则适用于 Java 和 super。虽然不完全一样。阅读this。
this 和 super 必须放在第一个的原因是,可以在调用实际的 this(x, y) 之前将字段设置为各种值。这意味着正在构造对象,并且在构造过程中可能引用该对象的任何线程都可以看到不同的值。
谢谢。