Làm thế nào là khớp mẫu trong Scala được thực hiện ở cấp độ mã byte?


123

Làm thế nào là khớp mẫu trong Scala được thực hiện ở cấp độ mã byte?

Nó giống như một loạt các if (x instanceof Foo)cấu trúc, hoặc cái gì khác? Ý nghĩa hiệu suất của nó là gì?

Ví dụ, được cung cấp mã sau (từ Scala By Ví dụ trang 46-48), mã Java tương đương cho evalphương thức sẽ như thế nào?

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 Tôi có thể đọc mã byte Java, vì vậy một đại diện mã byte sẽ đủ tốt cho tôi, nhưng có lẽ sẽ tốt hơn cho những người đọc khác biết nó trông như mã Java như thế nào.

PPS Cuốn sách Lập trình trong Scala có trả lời cho câu hỏi này và các câu hỏi tương tự về cách Scala được thực hiện không? Tôi đã đặt hàng cuốn sách, nhưng nó chưa đến.


Tại sao bạn không biên dịch ví dụ và phân tách nó bằng trình phân tách mã byte của Java?
Zifre

Có lẽ tôi sẽ làm điều đó, trừ khi ai đó đưa ra một câu trả lời tốt trước. Nhưng ngay bây giờ tôi muốn ngủ một chút. ;)
Esko Luontola

27
Câu hỏi rất hữu ích cho những độc giả khác!
djondal

1
@djondal: cách tốt nhất để nói điều đó chỉ là nêu lên câu hỏi :-)
Blaisorblade

Câu trả lời:


96

Mức độ thấp có thể được khám phá với trình dịch ngược nhưng câu trả lời ngắn gọn là đó là một bó if / elses trong đó vị ngữ phụ thuộc vào mẫu

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

Có nhiều hơn những gì bạn có thể làm với các mẫu như hoặc các mẫu và kết hợp như "trường hợp Foo (45, x)", nhưng nói chung đó chỉ là các phần mở rộng hợp lý của những gì tôi vừa mô tả. Các mẫu cũng có thể có các bộ bảo vệ, đó là các ràng buộc bổ sung trên các vị từ. Cũng có những trường hợp trình biên dịch có thể tối ưu hóa khớp mẫu, ví dụ khi có một số trùng lặp giữa các trường hợp, nó có thể kết hợp mọi thứ một chút. Các mẫu nâng cao và tối ưu hóa là một lĩnh vực hoạt động tích cực trong trình biên dịch, vì vậy đừng ngạc nhiên nếu mã byte cải thiện đáng kể các quy tắc cơ bản này trong các phiên bản hiện tại và tương lai của Scala.

Ngoài tất cả những điều đó, bạn có thể viết các trình trích xuất tùy chỉnh của riêng bạn ngoài hoặc thay vì các trình trích xuất mặc định mà Scala sử dụng cho các lớp tình huống. Nếu bạn làm như vậy, thì chi phí của mô hình khớp là chi phí của bất cứ điều gì trình trích xuất làm. Một tổng quan tốt được tìm thấy trong http://lamp.epfl.ch/~emir/written/MatchingObjectsWithPotypes-TR.pdf


Tôi tin rằng đây là liên kết hiện tại: infoscience.epfl.ch/record/98468/files/ mẹo
greenoldman

78

James (ở trên) nói điều đó tốt nhất. Tuy nhiên, nếu bạn tò mò thì luôn luôn là một bài tập tốt để xem mã byte bị tháo rời. Bạn cũng có thể gọi scalacvới -printtùy chọn, nó sẽ in chương trình của bạn với tất cả các tính năng dành riêng cho Scala. Về cơ bản, đó là Java trong trang phục của Scala. Đây là scalac -printđầu ra có liên quan cho đoạn mã bạn đã cung cấp:

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

Kể từ phiên bản 2.8, Scala đã có chú thích @switch . Mục tiêu là để đảm bảo rằng việc khớp mẫu sẽ được biên dịch thành các bảng biểu hoặc tra cứu thay vì một loạt các ifcâu lệnh có điều kiện .


6
Khi nào nên chọn @switch hơn thường xuyên?
Aravind Yarram

2
sử dụng @switchlà hiệu quả hơn so với kết hợp mẫu thông thường. vì vậy, nếu tất cả các trường hợp chứa giá trị không đổi, bạn nên luôn luôn sử dụng @switch(vì việc triển khai mã byte sẽ giống như của java switchthay vì nhiều if-if)
lev
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.