如何在字节码级别实现Scala中的模式匹配?

Esk*_*ola 118 performance scala bytecode pattern-matching

如何在字节码级别实现Scala中的模式匹配?

它是否像一系列if (x instanceof Foo)结构或其他东西?它的性能影响是什么?

例如,给定以下代码(来自Scala By Example第46-48页),该方法的等效Java代码如何eval

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)
}
Run Code Online (Sandbox Code Playgroud)

PS我可以读取Java字节码,因此字节码表示对我来说已经足够了,但是对于其他读者来说,知道它看起来像Java代码会更好.

PPS Scala编程是否能够解答这一问题以及有关Scala如何实现的类似问题?我订购了这本书,但尚未到货.

Jam*_*Iry 93

可以用反汇编程序探索低级别,但简短的回答是它是一堆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
Run Code Online (Sandbox Code Playgroud)

您可以使用"case Foo(45,x)"这样的模式或模式和组合做更多的事情,但通常这些只是我刚刚描述的逻辑扩展.模式也可以有守卫,这是对谓词的附加约束.在某些情况下,编译器可以优化模式匹配,例如,当案例之间存在一些重叠时,它可能会稍微合并一些事情.高级模式和优化是编译器中活跃的工作领域,因此如果字节代码在当前和未来版本的Scala中大大超过这些基本规则,请不要感到惊讶.

除此之外,除了Scala用于案例类的默认提取器之外,您还可以编写自己的自定义提取器.如果这样做,那么模式匹配的成本就是提取器所做的任何成本.http://lamp.epfl.ch/~emir/written/MatchingObjectsWithPatterns-TR.pdf中有一个很好的概述.


Jor*_*tiz 75

詹姆斯(上图)说得最好.但是,如果你很好奇,那么查看反汇编的字节码总是一个很好的练习.您也可以scalac使用该-print选项进行调用,该选项将打印您的程序,并删除所有Scala特定的功能.它基本上是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)
};
Run Code Online (Sandbox Code Playgroud)


om-*_*nom 32

从版本2.8开始,Scala就有了@switch注释.目标是确保将模式匹配编译为tableswitch或lookupswitch而不是一系列条件if语句.

  • 什么时候选择@switch而不是常规? (6认同)
  • 使用`@ switch`比常规模式匹配更有效。因此,如果所有情况都包含常量值,则应该始终使用`@ switch`(因为字节码实现将与Java`switch`相同,而不是许多if-else) (2认同)