Scala中的模式匹配如何在字节码级别实现?
Scala中的模式匹配如何在字节码级别实现?
它是否就像一系列if (x instanceof Foo)
构造,还是其他的? 它的性能影响是什么?
例如,给定以下代码(来自Scala示例页面46-48), eval
方法的等效Java代码将如何显示?
abstract class Expr case class Number(n: Int) extends Expr case class Sum(e1: Expr, e2: Expr) extends Expr def eval(e: Expr): Int = e match { case Number(x) => x case Sum(l, r) => eval(l) + eval(r) }
PS我可以读取Java字节码,所以一个字节码表示对我来说就足够了,但是对其他读者来说可能会更好地知道它是怎么样的Java代码。
PPS Scala编程书籍是否给出了有关Scala如何实现的类似问题的答案? 我已经订购了这本书,但还没有到。
低层次可以用反汇编来探讨,但简单的答案是,这是一堆if / elses谓词依赖于模式
case Sum(l,r) // instance of check followed by fetching the two arguments and assigning to two variables l and r but see below about custom extractors case "hello" // equality check case _ : Foo // instance of check case x => // assignment to a fresh variable case _ => // do nothing, this is the tail else on the if/else
还有更多的事情可以通过像“case Foo(45,x)”这样的模式或组合来完成,但是通常这些只是我刚刚描述的逻辑扩展。 模式也可以有警卫,这是对谓词的附加约束。 也有一些情况下,编译器可以优化模式匹配,例如,当情况有些重叠时,它可能会聚合一些东西。 高级模式和优化是编译器中一个活跃的工作领域,所以如果字节码在当前和未来版本的Scala中基本上超越了这些基本规则,那么不要感到惊讶。
除此之外,您还可以编写您自己的自定义提取器,或者替代Scala用于案例类的默认提取器。 如果这样做,那么模式匹配的成本就是提取器的成本。 在http://lamp.epfl.ch/~emir/written/MatchingObjectsWithPatterns-TR.pdf中find了一个很好的概述;
詹姆斯(上图)说得最好。 但是,如果您好奇,查看反汇编的字节码总是一个很好的练习。 你也可以使用-print
选项来调用scalac
,这个选项将会删除所有Scala特有的特性来打印你的程序。 这基本上是斯卡拉的服装中的Java。 下面是你给出的代码片段的相关scalac -print
输出:
def eval(e: Expr): Int = { <synthetic> val temp10: Expr = e; if (temp10.$isInstanceOf[Number]()) temp10.$asInstanceOf[Number]().n() else if (temp10.$isInstanceOf[Sum]()) { <synthetic> val temp13: Sum = temp10.$asInstanceOf[Sum](); Main.this.eval(temp13.e1()).+(Main.this.eval(temp13.e2())) } else throw new MatchError(temp10) };
自2.8版以来,Scala已经有了@switch注解。 目标是确保模式匹配将被编译为tableswitch或lookupswitch,而不是一系列的if
语句。