假设我在特征中定义了一些抽象值字段:
trait Base {
val toBeOverride: String
}
case class Impl(other:Int) extends Base {
override val toBeOverride = "some value"
}
如何编写一个函数,我可以轻松获取克隆实例,只覆盖toBeOverride
值,如下所示:
// copy only available to case class instance
// v does not have method 'copy'
def overrideBaseValue[T <: Base](v: Base) =
v.copy(toBeOverride = "prefix" + v.toBeOverride)
修改
@ som-snytt,我不认为这是重复的,就像Trait
与Abstract Class
不同。这个问题的答案不满足我,见下文。
@Blaisorblade,是的,这是一个问题。对于每个子案例类的实例,toBeOverride
字段是相同的,因此它不应出现在构造函数中。
现在所有的建议都是在每个(!)子案例类中定义一个自定义的copy
方法,在我看来这个方法很难看,并且显示了该语言的无能力。
答案 0 :(得分:1)
最简单的解决方案是只需添加您想要的方法:
trait Base {
val toBeOverride: String
def copyBase(newToBeOverridden: String): Base
}
case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base {
def copyBase(newToBeOverridden: String) = copy(toBeOverride = newToBeOverridden)
}
这也允许在指定Impl
的值时直接创建toBeOverride
的实例(这是不可能的)。唯一的缺点是现在使用Impl的模式匹配必须更改语法 - 如果这是一个问题,请更新您的问题并添加注释。
顺便说一句,如果您只想添加前缀(如您的示例所示),那就没问题了:
case class Impl(other:Int, override val toBeOverride: String = "some value") extends Base {
def copyBase(newToBeOverridden: String) = copy(toBeOverride = toBeOverride + newToBeOverridden)
}
答案 1 :(得分:1)
这是两种机制。
显然,在不久的将来,你将能够编写一个可以发出匿名子类的宏,但在那之前,我认为这个类型类并不是很艰难。
在这里开动动态轮胎。
import scala.language.dynamics
import scala.reflect._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.runtime.universe._
trait Base {
def m: String
}
case class Impl(p: Int) extends Base {
override val m = "some value"
}
trait Basic extends Dynamic {
protected def m: String
def selectDynamic(f: String): Any =
if ("m" == f) m else reflecting(this, f)
protected def reflecting(b: Basic, f: String) = {
val im = cm.reflect(b)
val member = im.symbol.typeSignature member newTermName(f)
require(member != NoSymbol, s"No such member $f")
(im reflectMethod member.asMethod)()
}
}
case class Implic(p: Int) extends Basic {
override protected val m = "some value"
}
object Test extends App {
implicit class Copy[A <: Base](val b: A) {
def overriding(overm: String): A = (b match {
case impl: Impl => new Impl(impl.p) { override val m = overm }
case b: Base => new Base { override val m = overm }
}).asInstanceOf[A]
}
implicit class Proxy[A <: Basic : ClassTag](val b: A) {
def proximately(overm: String): Basic = new Basic {
override val m = overm
override def selectDynamic(f: String): Any =
if ("m" == f) overm else reflecting(b, f)
override def toString = b.toString
}
}
// asked for this
//def overriding[T <: Base](v: Base) = v.copy(m = "prefix" + v.m)
/* want something like this
def overriding[T <: Base](v: Base) = new Impl(v.p) {
override val m = "some value"
} */
val a = Impl(5)
val b = a overriding "bee good"
Console println s"$a with ${a.m} ~> $b with ${b.m}"
// or
val c = Implic(7)
val d = c proximately "dynomite"
Console println s"$c with ${c.m} ~> $d with ${d.m}"
}
答案 2 :(得分:0)
由于特征不会自动获得复制方法,您可以尝试使用Base
案例类:
case class Base(toBeOverride: String)
case class Impl(other: Int, someVal: String = "some value") extends Base(someVal)
def overrideBaseValue[T <: Base](v: Base) =
v.copy(toBeOverride = "prefix" + v.toBeOverride)
您遇到的问题是,copy
会返回Base
的实例,我认为您无法将其转换回原来的Impl
}类。例如,这不会编译:
def overrideBaseValue[T <: Base](v: T): T =
v.copy(toBeOverride = "prefix" + v.toBeOverride)