我有一个基本的Table
/ Column
DSL定义。
import scala.collection.parallel.mutable.ParHashSet
abstract class Column[Owner <: Table[Owner, Record], Record, ValueType](table: Table[Owner, Record]) {
table.addColumn(this)
}
class Table[Owner <: Table[Owner, Record], Record] {
private[this] val _columns = ParHashSet.empty[Column[Owner, Record, _]]
def columns: List[Column[Owner, Record, _]] = _columns.toList
def addColumn(column: Column[Owner, Record, _]) {
_columns += column
}
}
class SpecialColumn[Owner <: Table[Owner, Record], Record, ValueType](table: Table[Owner, Record]) extends Column[Owner, Record, ValueType](table) {//blabla}
关键是要像这样定义Table
:
case class SomeModel(name: String, prop: String)
sealed class SomeTable extends Table[SomeTable, SomeModel] {
object name extends Column[SomeTable, SomeModel, String](this)
object prop extends SpecialColumn[SomeTable, SomeModel, String](this)
}
object SomeTable extends SomeTable {}
我希望SomeTable
存储对其中定义的对象的引用。因此Column
构造函数在实例化时调用addColumn
。
因此SomeTable.columns.length
应该是2,但它总是1。
我在这里缺少什么? Here's斯卡拉小提琴。
答案 0 :(得分:0)
object name
和object prop
是声明。他们的构造函数在被引用之前不会被调用。
尝试更改为
class SomeTable extends Table[SomeTable, SomeModel] {
object name extends Column[SomeTable, SomeModel, String](this)
object prop extends SpecialColumn[SomeTable, SomeModel, String](this)
val n = name
val p = prop
}
了解它如何改变测试结果。
我的偏好实际上是
class SomeTable extends Table[SomeTable, SomeModel] {
val name = new Column[SomeTable, SomeModel, String](this) {}
val prop = new SpecialColumn[SomeTable, SomeModel, String](this)
}
避免同时具有声明和引用的冗余,并使列的初始化具有确定性。
正如此问题所示,Scala中object
的非确定性初始化是您必须注意的事项。
答案 1 :(得分:0)
这是懒惰评估的效果。 JVM上的对象会被懒惰地创建,并且在第一次使用/引用时,会根据需要懒惰地加载类。
println(s"Number of columns: ${SomeTable.columns.length}")
// prints 0
SomeTable.name
SomeTable.prop
println(s"Number of columns: ${SomeTable.columns.length}")
// prints 2
因此,只需引用字段,就可以在上面的示例中初始化它们。
如果您更改了以下代码:
class SomeTable extends Table[SomeTable, SomeModel] {
object name extends Column[SomeTable, SomeModel, String](this)
object prop extends SpecialColumn[SomeTable, SomeModel, String](this)
}
为:
class SomeTable extends Table[SomeTable, SomeModel] {
val name = new Column[SomeTable, SomeModel, String](this){}
val prop = new SpecialColumn[SomeTable, SomeModel, String](this)
}
您将根据需要始终打印2
。
它的工作原理是,在第一种情况下,object
字段Scala会在您引用它们时创建这些对象,但在第二种情况下,您正在初始化变量,因此必须计算值。请注意,您无法覆盖子类中的object
字段,但您可以覆盖val
或def
- 所以有一些“小?”差异。