我有一个 Scala 问题。想象一下您正在构建代码来处理不同的操作,即
operation match {
case A => doA()
case B => doB()
case _ => throw new Exception("Unknown op: " + operation)
}
现在,想象一下,稍后您想要构建一个新版本,并且想要扩展操作 C 的模式匹配。如何才能以这样的方式实现操作分辨率仍为 O(1)?
我的意思是,我可以修改上面的代码来执行以下操作:
case _ => handleUnknownOperation(operation)
子类可以实现handleUnknownOperation来执行以下操作:
operation match {
case C => doC()
}
但这很糟糕,因为这意味着 C 操作需要 O(2)。
扩展这种模式匹配结构的任何其他想法或最佳实践?
干杯, 加尔德
最佳答案
为了回答最初的问题,模式匹配被有效地转换为一系列 if/else 语句,只是一系列测试。最后的 case _
只是一个失败(没有关联的测试)。因此,在一场比赛中拥有 A、B 和 C 以及一场比赛中存在 A 和 B 然后委托(delegate)给另一场与 C 匹配的比赛之间没有什么区别。以下为例:
class T
case class A(v: Int) extends T
case class B(v: Int) extends T
case class C(v: Int) extends T
class Foo {
def getOperation(t: T): Unit = {
t match {
case A(2) => println("A")
case B(i) => println("B")
case _ => unknownOperation(t)
}
}
def unknownOperation(t: T): Unit = println("unknown operation t=" + t)
}
class Bar extends Foo {
override def unknownOperation(t: T): Unit = t match {
case C(i) => println("C")
case _ => println("unknown operation t=" + t)
}
}
使用jad反编译Foo.class,得到:
public void getOperation(T t) {
label0:
{
T t1 = t;
if(t1 instanceof A)
{
if(((A)t1).v() == 2)
{
Predef$.MODULE$.println("A");
break label0;
}
} else
if(t1 instanceof B)
{
Predef$.MODULE$.println("B");
break label0;
}
unknownOperation(t);
}
}
所以,我想说你不应该担心性能[*]。
但是,从设计的角度来看,我可能会稍微改变一下,或者像 Frank 建议的那样使用命令模式,或者不重写子类中的 unknownOperation
,您可以重写 getOperation
,它与 C 进行匹配,然后委托(delegate)给 super.getOperation()
,这对我来说似乎更简洁。
class Bar extends Foo {
override def getOperation(t: T): Unit = t match {
case C(i) => println("C")
case _ => super.getOperation(t)
}
}
[*] 需要注意的是复杂性。 Scala 2.10 之前的版本存在一个问题,其中模式匹配器生成的 .class 文件过于复杂 ( nested extractors generate exponential-space bytecode ),因此如果您使用的匹配非常复杂,这可能会导致问题。这个问题在 2.10 中通过虚拟模式匹配器得到了修复。如果您遇到此问题,那么解决此错误的方法之一是将模式匹配拆分为不同的方法/类。
关于scala - 在子类中扩展 Scala 模式匹配,同时保持复杂性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9194428/