让我们假设我们有一个共同的特质模型。
trait Model {
def id: String
def updated: Date
}
我们有2个案例类来扩展这个特性。
case class C1(id: String, updated: Date, foo: String) extends Model
case class C2(id: String, updated: Date, bar: Int) extends Model
是否可以编写如下所示的实用程序函数,该函数将Model作为参数并返回带有更新字段的更新值的副本?
object Model {
def update[T <: Model](model: T): T = {
model.copy(updated = new Date) // This code does not compile.
}
}
答案 0 :(得分:4)
你可以在这里写的“最佳”抽象是Lens
,它看起来像:
trait Lens[A, B]{
def get: A => B
def set: (A, B) => A
}
以便您的代码如下:
def update[A](that: A, value: Date)(implicit tLens: Lens[A, Date]): A =
tLens set (that, value)
答案 1 :(得分:3)
您的代码有两个问题:
copy
未在特征上定义,因此您需要在特征上定义可以使用的特征。update
返回T
而不是Model
,每个Model
必须知道其实际的子类型。你可以这样解决:
trait Model[T <: Model[T]] {
def id: String
def updated: Date
def withDate(d: Date): T
}
case class C1(id: String, updated: Date, foo: String) extends Model[C1] { def withDate(d: Date) = copy(updated = d) }
case class C2(id: String, updated: Date, bar: Int) extends Model[C2] { def withDate(d: Date) = copy(updated = d) }
object Model {
def update[T <: Model[T]](model: T): T = {
model.withDate(new Date) // This code does not compile.
}
}
现在它起作用了:
scala> val c1 = C1("test", new Date, "foo")
c1: C1 = C1(test,Mon Apr 21 10:25:10 CDT 2014,foo)
scala> Model.update(c1)
res0: C1 = C1(test,Mon Apr 21 10:25:17 CDT 2014,foo)
答案 2 :(得分:1)
copy
是在您的案例类中定义的方法。不在您的基本特征Model
上。如果你有这个怎么办:
trait Model {
def id: String
def updated: Date
}
case class C1(id: String, updated: Date, foo: String) extends Model
case class C2(id: String, updated: Date, bar: Int) extends Model
class NotACaseClass(val id: String, val updated: Date) extends Model
NotACaseClass
是Model
的非常有效的孩子,您可以将其实例传递给update
函数,但祝您找到copy
方法:)