我在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类时可以在其他任何地方使用它。如果可能的话,我想避免这种情况。
答案 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
但您无法从外部代码访问令牌,因为val
为protected
。
希望这是足够好的封装。