如何匹配实现多个特质的对象的模式?

4

我有一个超类Command,许多不同的子类从Command继承,并且同时可能还继承了这些特征之一或多个:ValuesCommandKeysCommandMembersCommand 等等。

现在我想匹配所有继承了 ValuesCommandKeysCommandCommand 实现。

这是我想要实现的伪代码

def apply(cmd : Command) = {
  cmd match {
    case c:(ValuesCommand && KeysCommand) => c.doSomething()
  }
}

我可以回退到匹配第一个特征并嵌套第二个match。但我实际上并不需要它,而且看起来很糟糕。


也许更好的方法是在特质 ValuesCommandKeysCommand 中覆盖(或抽象覆盖)doSomething 方法?这样你就不需要执行模式匹配了。 - maks
我很想这样做,但是我正在处理的代码不是我的:它来自一个库(Finagle Redis),我不想进行分支。 - sscarduzio
1个回答

11

你可以这样做:

def apply(cmd : Command) = {
  cmd match {
    case c: ValuesCommand with KeysCommand => c.doSomething()
  }
}

当你有一个类(例如这里的 ValKey)既扩展了 ValuesCommand 又扩展了 KeysCommand,那么你也会拥有类似以下的东西:

class ValKey extends ValuesCommand with KeysCommand`

编辑(您的评论):

我无法想象在这种情况下您需要像 ValuesCommand 或 KeysCommand 这样的东西。您可以阅读 @Randall Schulz 评论中的链接,以了解如何获取OR。

让我们假设您已经有了OR(v),就像链接中描述的那样。

case c: ValuesCommand v KeysCommand => //soo.. what is c?

现在你仍然需要对c进行模式匹配,以找出它是什么类型的命令。(很可能)

因此最终你仍可以直接这样做:

cmd match {
  case vc: ValuesCommand => vc.doSomething()
  case kc: KeysCommand   => kc.doSomehtingElse()
}

编辑2:

如果你想在cmd上调用你的accept方法,只有当它是ValuesCommandKeysCommand时,你可以这样做:

cmd match {
  case _: ValuesCommand | _: KeysCommand => accept(cmd)
}

我猜这样比较DRY

cmd match {
  case vc: ValuesCommand => accept(cmd)
  case kc: KeysCommand   => accept(cmd)
}

在逻辑术语中,“with”是连词。两种类型标识必须同时存在才能获得它。令人惊讶的是,Scala可以获得未装箱的静态“分离式”(或者,也就是“联合”)类型组合!请参见http://www.chuusai.com/2011/06/09/scala-union-types-curry-howard/以获取所有乐趣。 - Randall Schulz
with 很完美,对我来说很有意义。但是 || 呢? 例如: case c:(ValuesCommand || KeysCommand) => c.doSomething() - sscarduzio
我不明白为什么OR是一个奇怪的情况:在那个模式匹配中,我想调用accept(cmd: Command)函数,无论是KeysCommand还是ValuesCommand对象。我不需要知道or条件的哪一部分已经匹配,因为从现在开始我将把对象视为“Command”。当然,你使用“v”的伪代码应该省略“c:”,因为你会直接引用对象作为cmd,我想。 - sscarduzio
完美,那正是我想要的。非常感谢您,先生。 - sscarduzio

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