Scala:存储具有可变类型的对象

时间:2014-01-26 00:44:28

标签: scala

我有一个基本的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斯卡拉小提琴。

2 个答案:

答案 0 :(得分:0)

object nameobject 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字段,但您可以覆盖valdef - 所以有一些“小?”差异。