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

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

我正在为 ORM 中的模型使用案例类。每个模型都有一个 ID,但 ID 不应公开访问。所以我有 parent 特质

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。

因为我有很多这样的案例类,所以我希望案例类本身的代码尽可能少。因此,在每个案例类中实现一个 copy() 方法会产生大量样板代码。

有没有办法在 trait 中实现某些东西,使 copy() 也复制 id?也许使用宏的东西?还是有其他我根本没有想到的方法?

编辑:

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

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

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

最佳答案

如果我是你,我会添加一个携带 ID 的 token :

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) }
}

由于构造函数对您的包是私有(private)的,因此除了您之外没有其他人可以创建这些标记。

然后你把你的特质写成

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

但是您不能从外部代码访问 token ,因为 valprotected

希望这是足够好的封装。

关于调用 copy() 时父特性的 Scala Case 类复制成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22049523/

相关文章:

java - Scala,不喜欢 java 集合 API?

scala - 记录 Scala 2.10 宏

scala - 是否可以使用 SBT 的反射?

scala - 如何将准引号与先前定义的对象一起使用

scala - 如何在 Scala 宏中构造通配符类型?

scala - 在 selectDynamic 的宏实现中调用实例方法

斯卡拉 3 : inline vs quoted (macros)

ruby-on-rails - Scala + Lift 或 Ruby on Rails,适合初学者

list - 如何以功能样式从列表中添加选择性行的值?

Scala 2.10 和包反射