Scala의 패턴 일치는 바이트 코드 수준에서 어떻게 구현됩니까?


123

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 코드로 어떻게 생겼는지 아는 것이 더 나을 것입니다.

PPS Programming in Scala 책 은 Scala가 어떻게 구현되는지에 대한 이와 유사한 질문에 대한 답을 제공합니까? 책을 주문했지만 아직 도착하지 않았습니다.


그냥 예제를 컴파일하고 자바 바이트 코드 디스어셈블러로 디스 어셈블하지 않는 이유는 무엇입니까?
Zifre 2009

누군가가 먼저 좋은 대답을하지 않는 한 그렇게 할 것입니다. 하지만 지금은 좀 자고 싶어요. ;)
Esko Luontola 2009

27
이 질문은 다른 독자들에게 유용합니다!
djondal 2011-07-03

1
@djondal : 그 말을하는 가장 좋은 방법은 :-) 질문을 upvote에 단지입니다
Blaisorblade

답변:


96

낮은 수준은 디스어셈블러로 탐색 할 수 있지만 짧은 대답은 술어가 패턴에 따라 달라지는 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에 좋은 개요가 있습니다.



78

James (위)가 가장 잘 말했습니다. 그러나 궁금하다면 디스 어셈블 된 바이트 코드를 보는 것이 항상 좋은 연습입니다. 옵션을 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)
};

34

버전 2.8부터 Scala에는 @switch 주석이 있습니다. 목표는 패턴 일치가 일련의 조건문 대신 테이블 스위치 또는 조회 스위치 로 컴파일되도록하는 것 if입니다.


6
언제 @switch를 선택해야합니까?
Aravind Yarram

2
사용 @switch은 일반 패턴 일치보다 효율적입니다. 따라서 모든 경우에 상수 값이 포함 된 경우 항상 사용해야합니다 @switch(바이트 코드 구현이 switch많은 if-else 대신 java와 동일하므로 )
lev
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.