我正在尝试基于某种具体类型的实例创建一个新实例.我有一组类型为{B,C}的类型为A类的子类型,我需要一些可调用形式的实用程序,它将采用任何现有的{B,C}实例并允许创建新实例(允许构造) )基于那种类型.
trait A case class B(name: String) extends A case class C(name: String) extends A // I hoped something like this would work, but it doesn't. def newALike[T <: A](instance: T): T = instance.copy(name = instance.name + "_new")
所需用法:
val b = B("B") val c = C("C") val newB = newALike(b) newB.name // B_new val newC = newALike(c) newC.name // C_new
Ben Kovitz.. 5
这将有效,但它可能需要大量重复的代码,具体取决于您的应用程序的具体情况:
trait A { def name: String } case class B(override val name: String) extends A case class C(override val name: String) extends A trait CanCopy[T] { def copy(t: T, newName: String): T } implicit object canCopyB extends CanCopy[B] { override def copy(b: B, newName: String) = b.copy(name=newName) } implicit object canCopyC extends CanCopy[C] { override def copy(c: C, newName: String) = c.copy(name=newName) } def newALike[T <: A](instance: T)(implicit ev: CanCopy[T]): T = ev.copy(instance, instance.name + "_new")
问题是特征A无法知道如何构造子类实例的具体细节.正如Scala编译器所看到的那样,没有人知道你可以定义什么作为特征A的扩展,或者它的构造函数可能采用什么参数.CanCopy和隐式对象告诉Scala编译器" 这就是你如何构造一个B,这就是你构造一个C的方法." 隐式参数的名称是ev
,代表"证据":它告诉编译器查找可以复制类型T的证据,并且证据由可以完成工作的对象提供.
根据您的应用程序,您可以通过定义另一个特征来避免一些重复的代码,该特征扩展了A,并且B和C扩展,这可以保证.copy
具有特定参数的方法可用.然后你可以有一个类型的隐式对象CanCopy[ThatIntermediaryTrait]
,它知道调用该.copy
方法.
这将有效,但它可能需要大量重复的代码,具体取决于您的应用程序的具体情况:
trait A { def name: String } case class B(override val name: String) extends A case class C(override val name: String) extends A trait CanCopy[T] { def copy(t: T, newName: String): T } implicit object canCopyB extends CanCopy[B] { override def copy(b: B, newName: String) = b.copy(name=newName) } implicit object canCopyC extends CanCopy[C] { override def copy(c: C, newName: String) = c.copy(name=newName) } def newALike[T <: A](instance: T)(implicit ev: CanCopy[T]): T = ev.copy(instance, instance.name + "_new")
问题是特征A无法知道如何构造子类实例的具体细节.正如Scala编译器所看到的那样,没有人知道你可以定义什么作为特征A的扩展,或者它的构造函数可能采用什么参数.CanCopy和隐式对象告诉Scala编译器" 这就是你如何构造一个B,这就是你构造一个C的方法." 隐式参数的名称是ev
,代表"证据":它告诉编译器查找可以复制类型T的证据,并且证据由可以完成工作的对象提供.
根据您的应用程序,您可以通过定义另一个特征来避免一些重复的代码,该特征扩展了A,并且B和C扩展,这可以保证.copy
具有特定参数的方法可用.然后你可以有一个类型的隐式对象CanCopy[ThatIntermediaryTrait]
,它知道调用该.copy
方法.