调用copy()时父级特征的Scala Case类复制成员

时间:2014-02-26 18:02:05

标签: scala scala-2.10 scala-macros case-class

我在ORM中使用案例类用于模型。每个模型都有一个id,但id不应公开访问。所以我有一个父特质

trait WithId {
  private var id: Long = 0
}

以及很多继承自它的案例类(模型)

case class C1(a: Int, b: String) extends WithId
case class C2(...) extends WithId
...

现在,如果有人在案例类上调用copy(),它不会使用它复制id,而是将其设置为0.

val c1 = C1(3, "bla")
//Set c1.id to a value != 0
val c2 = c1.copy(b="bla2")
//c1.id !=0, but c2.id = 0

我希望它也能复制id。

由于我有很多这些案例类,我宁愿在案例类中拥有尽可能少的代码。因此,在每个case类中实现copy()方法将是很多样板代码。

有没有办法在trait中实现使copy()也复制id的东西?也许使用宏的东西?还是有另一种我根本没想过的方式?

修改

我可以覆盖每个案例类中的id字段,如

case class C1(a: Int, b: String, protected var id: Long)

然后它会被复制。但这也是我必须为每个案例类编写的样板代码,并且很难解释为什么你必须在案例类中添加一个id字段,尽管你从未注意到它或者在使用case类时可以在其他任何地方使用它。如果可能的话,我想避免这种情况。

1 个答案:

答案 0 :(得分:1)

如果我是你,我会添加一个携带身份证的令牌:

class IdToken private[myPackage] (val id: Int) {
  override def equals(a: Any) = a match {
    case tok: IdToken => id == tok.id
    case _ => false
  }
  override def hashCode = id.hashCode ^ 0x157135
  override def toString = ""
}
object IdToken {
  private var lastId = 0
  private[myPackage] def next = { lastId += 1; new IdToken(lastId) }
}

由于构造函数对您的包是私有的,除了您之外没有其他人可以创建这些令牌。

然后你写下你的特质

trait WithID { protected def idToken: IdToken }

case class C1(a: Int, b: String, protected val idToken: IdToken = IdToken.next) extends WithID {
  def checkId = idToken.id
}

(下面的测试只需要checkId),所以你可以

scala> C1(5, "fish")
res1: C1 = C1(5,fish,)

scala> res1.copy(a = 3)
res2: C1 = C1(3,fish,)

scala> res1.checkId == res2.checkId
res3: Boolean = true

但您无法从外部代码访问令牌,因为valprotected

希望这是足够好的封装。