在Scala中创建现有对象类型的新实例

mar*_*oss 3 scala

我正在尝试基于某种具体类型的实例创建一个新实例.我有一组类型为{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") 
Run Code Online (Sandbox Code Playgroud)

所需用法:

val b = B("B")
val c = C("C")

val newB = newALike(b)
newB.name // B_new

val newC = newALike(c)
newC.name // C_new
Run Code Online (Sandbox Code Playgroud)

Ben*_*itz 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")
Run Code Online (Sandbox Code Playgroud)

问题是特征A无法知道如何构造子类实例的具体细节.正如Scala编译器所看到的那样,没有人知道你可以定义什么作为特征A的扩展,或者它的构造函数可能采用什么参数.CanCopy和隐式对象告诉Scala编译器" 就是你如何构造一个B,就是你构造一个C的方法." 隐式参数的名称是ev,代表"证据":它告诉编译器查找可以复制类型T的证据,并且证据由可以完成工作的对象提供.

根据您的应用程序,您可以通过定义另一个特征来避免一些重复的代码,该特征扩展了A,并且B和C扩展,这可以保证.copy具有特定参数的方法可用.然后你可以有一个类型的隐式对象CanCopy[ThatIntermediaryTrait],它知道调用该.copy方法.

  • 在case类中你不需要`override val` (3认同)