Scala中的逐案例继承

13

我有一个抽象类,我扩展它并创建了许多案例类。现在我想复制这些案例类的实例,只需更改第一个参数,因此我使用案例类的copy方法。

由于我必须对所有已从公共抽象类扩展的案例类执行此操作,而不是为所有案例类执行此操作,因此我尝试将其通用化,并使抽象类成为案例类。

然后Scala给我这个:

  

案例祖先生物的案例类章鱼,但禁止案例到案例的继承。要克服此限制,请使用提取器在非叶节点上进行模式匹配。

代码:

abstract class Organism(legs: Int)
case class Octopus(override val legs: Int, weight: Double, ...)
case class Frog(override val legs: Int, ...)
def clone(o: Organism) = o.copy(legs = -1)

这就是我想做的。但如果我无法让 clone 方法起作用,那么我将不得不为 OctopusFrog 都进行复制。

有什么建议可以减少这种冗长吗?

2个回答

11

你不能通用地抽象出case class的copy方法。我建议使用Shapeless或Monocle中的Lenses:

trait Organism { def legs: Int }
// monocle @Lenses uses a macro to generate lenses
@Lenses case class Octopus(override val legs: Int, weight: Double, ...)
  extends Organism
@Lenses case class Frog(val legs: Int, ...) extends Organism

def clone[O <: Organism](o: O, legsLens: Lens[O, Int]): O =
  legsLens.set(-1)(o)

val myOctopus = Octopus(8, 2.4, ...)
val myFrog = Frog(2, ...)

// use the generated Lenses
val cloneOctopus: Octopus = clone(myOctopus, Octopus.legs)
clone(myFrog, Frog.legs)

1

仅使用标准的 Scala,抽象(超级)类上没有通用的复制方法:它如何知道所有子类如何克隆/复制?特别是将来可能会添加新的子类。

据我所知,实现此类抽象方法的两种主要方法是:

1)创建一个匹配所有子类的函数:

def clone(o: Organism) = o match {
  case o: Octopus => o.copy(legs = -1) 
  case f: Frog    => f.copy(legs = -1) 
}

每次添加新的子类时,都需要将其添加到这些函数中。这最适用于使用sealed abstract class
2)向抽象API添加一个makeClone方法(保留名称clone)。
abstract class Organism(legs: Int){
  def makeClone(legNumber: Int): Organism
}
case class Octopus(legs: Int, weight: Double) extends Organism(legs) {
  def makeClone(legNumber: Int) = this.copy(legs = legNumber)
}

请注意,虽然(1)中的函数始终返回一个Organism,但是这里的方法Octopus.makeClone返回一个Octopus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接