首页 文章

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

提问于
浏览
114

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

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

例如,给定以下代码(来自Scala By Example第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)
}

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

P.P.S.书Programming in Scala是否给出了关于Scala如何实现的类似问题的答案?我订购了这本书,但尚未到货 .

3 回答

  • 91

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

  • 73

    可以用反汇编程序探索低级别,但简短的回答是它是一堆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中有一个很好的概述

  • 30

    詹姆斯(上图)说得最好 . 但是,如果你查看反汇编的字节码总是很好的练习're curious it' . 您还可以使用 -print 选项调用 scalac ,该选项将打印您的程序,并删除所有Scala特定的功能 . 它's basically Java in Scala'的服装 . 以下是您提供的代码段的相关 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)
    };
    

相关问题