在scala中,如何使抽象类中的子类参数可用于模式匹配?

2skhul33  于 2023-03-12  发布在  Scala
关注(0)|答案(2)|浏览(130)

我有一个类和两个case子类:

abstract class C
case class C1(left: C, right: C, weight: Int) extends C
case class C2(weight: Int) extends C

我想实现类似下面的内容:

def weight(t: C): Int = {
    t match {
      case c1: C1 => l.weight
      case c2: C2 => c2.left.weight + c1.right.weight //this line doesn't let the code compile
    }
  }

上面的代码不能编译。leftright没有属性weight。我看到这个是因为C没有为它定义权重。只有c1c2有。但是,我传递给weight函数的类示例将是c1c2,并且肯定有权重。
它实际上是树上的递归权重求和,我可以通过以下方式实现:

def weight(t: C): Int = {
    t match {
      case c1: C1 => l.weight
      case c2: C2 => weight(c2.left) + weight(c1.left)
    }
  }

但是,我不想递归,我不认为我应该必须,如果重量信息是简单地在那里,我传入的示例可用。
这是我要解决的一个分配问题,类CC1C2的签名是神圣不可侵犯的。

abstract class C

abstract class C:
    val weight: Int = ???

但是,这会引起C1C2签名中的weight变量的问题,并要求我覆盖它。
我尝试并认为可行的一个解决方案是创建一个伴随对象:

abstract class CodeTree
object CodeTree:
  val weight: Int = ???
case class Fork(left: CodeTree, right: CodeTree, chars: List[Char], weight: Int) extends CodeTree
case class Leaf(char: Char, weight: Int) extends CodeTree

但是我认为伴随对象不会被子类继承

  • 我如何在不递归的情况下获得想要的结果?
  • 更广泛地说,我如何赋予一个抽象类-- * 这个特定的字段在继承自我的子类中总是可用的,因此它应该是静态可用的,并且不会编译失败 *?
68de4m5k

68de4m5k1#

您应该将成员weight: Int添加到C

abstract class C:
  def weight: Int
case class C1(left: C, right: C, weight: Int) extends C
case class C2(weight: Int) extends C

然后您可以匹配键入的模式

def weight(t: C): Int =
  t match
    case c1: C1 => c1.left.weight + c1.right.weight
    case c2: C2 => c2.weight

或构造函数模式

def weight(t: C): Int = 
  t match 
    case C1(l, r, _) => l.weight + r.weight
    case C2(w)       => w

Why do we have a need for separate case identifiers in case of type only matching in scala?
通常,抽象成员是def s,在实现中被def/val/lazy val(如果需要,为var)覆盖。

nr7wwzry

nr7wwzry2#

weight添加到超类中是正确的方法,但是实际上必须在C1中 * 定义 * weight,这导致不需要开始模式匹配。

abstract class C { def weight: Int }
case class C1(left: C, right: C) extends C { def weight = left.weight + right.weight } 
case class C2(weight: Int) extends C

def weight(t: C) = t.weight

相关问题