Scala中复制带trait的case class实例如何保留混入的trait?
问题原因
- Scala 编译器为 case class 自动生成的
copy方法是定义在 case class 本身的类结构中的,返回值类型固定为原 case class 类型,不会携带实例动态混入的 trait 信息。 - 你示例中的
aa是实例化时动态混入Tailtrait 的特例,Tail不属于Cat类原生的继承链,copy方法感知不到这个动态混入的特征,因此返回的新实例只会是原生的Cat类型,不会继承Tail。
解决方案
方案1:类定义阶段直接混入trait
如果业务上所有Cat实例都需要携带Tail特征,直接修改Cat类的定义,将trait Tail提前混入类继承链,这样所有copy出来的实例会自动携带该 trait:
trait Tail case class Cat(name: String) extends Tail val aa = Cat("bob") val bb = aa.copy(name = "ted") // bb类型为Cat,原生继承Tail
方案2:实例复制时手动重新混入trait
如果不能修改原有Cat类的定义,只能使用动态混入的场景,复制的时候手动创建新的带混入的实例:
trait Tail case class Cat(name: String) val aa = new Cat("bob") with Tail // 复制时重新创建带Tail的实例 val bb = new Cat(aa.copy(name = "ted").name) with Tail // 或者简化写法,不需要调用原生copy: val bb2 = new Cat(name = "ted") with Tail
方案3:自定义扩展方法简化调用
如果需要频繁复制带Tail的Cat实例,可以给Cat with Tail类型扩展专用的复制方法,避免每次手动写混入逻辑:
// Scala 3 扩展方法写法 extension (c: Cat with Tail) def copyWithTail(name: String = c.name): Cat with Tail = new Cat(name) with Tail // 使用方式 val aa = new Cat("bob") with Tail val bb = aa.copyWithTail(name = "ted") // 直接返回Cat with Tail类型
注意:不要直接对原生copy返回的Cat实例强转为Cat with Tail,该实例实际运行时并没有混入trait,强转会触发ClassCastException
内容的提问来源于stack exchange,提问作者gav.newalkar
相关产品推荐
相关产品推荐

