2013-07-01 52 views
12

Tôi chỉ nhận thấy rằng Scala có macro, nhưng tôi chưa bao giờ thấy bất kỳ mã nào sử dụng chúng. Họ cũng có vẻ khá khác với các macro tiền xử lý C và các loại tương tự. Đọc qua overview các macro, có vẻ như chúng không cung cấp bất kỳ thứ gì trước đây không thể có trong Scala. Dưới tiêu đề động lực, có một danh sách những thứ mà macro cho phép:Macro Scala, chúng được sử dụng ở đâu?

  • ảo hóa Ngôn ngữ (quá tải/trọng ngữ nghĩa của các ngôn ngữ lập trình ban đầu để cho phép nhúng sâu của DSL),
  • reification Chương trình (cung cấp các chương trình với phương tiện để kiểm tra mã riêng của họ),
  • tự tối ưu hóa (tự áp dụng các tên miền cụ thể tối ưu hóa dựa trên chương trình reification),
  • chương trình thuật toán xây dựng (thế hệ mã tẻ nhạt để viết với các tóm tắt được hỗ trợ bởi ngôn ngữ lập trình).

Sau đó trong menu, có những tính năng vĩ mô thực nghiệm, chẳng hạn như các macro loại, quasiquotes, macro untyped và thậm chí nhiều hơn nữa. Rõ ràng là có nhu cầu về điều này!

Tất cả những tính năng này có vẻ thú vị cho những người xây dựng thư viện rất tinh vi với sự hiểu biết mạnh mẽ về Scala. Nhưng macro có cung cấp cái gì đó cho nhà phát triển Scala trung bình không? Việc sử dụng các macro có làm cho mã Scala của tôi tốt hơn không?

+1

Bạn có thể có một cái nhìn vào tờ giấy mới nhất của chúng tôi vạch ra một số các tập quán thú vị của macro: http://scalamacros.org/ paperstalks/2013-04-22-LetOurPowersCombine.pdf. –

+0

Đây là một bài viết về trang web doc dành riêng: http://docs.scala-lang.org/overviews/macros/usecases.html –

Trả lời

17

Là nhà phát triển Scala "trung bình", bạn rất có thể sẽ không tự viết macro, trừ khi bạn có lý do rất tốt.

Macro là phương pháp lập trình meta thời gian biên dịch, tức là chương trình chương trình của bạn. Ví dụ, một def-macro - là một phần của Scala 2.10 mặc dù vẫn là "thử nghiệm" - trông giống như một phương thức thông thường, nhưng bất cứ khi nào bạn gọi phương thức đó trong mã của bạn, trình biên dịch sẽ thay thế cuộc gọi đó bằng bất kỳ macro nào ẩn đằng sau phương thức đó sẽ tạo ra (một đoạn mã mới).


Ví dụ rất đơn giản. Kết hợp ngày khi dự án của bạn đã được biên soạn vào mã:

import java.util.Date 
import reflect.macros.Context 
import language.experimental.macros 

object CompileTime { 
    def apply(): Date = macro applyImpl 

    def applyImpl(c: Context)(): c.Expr[Date] = { 
    import c.universe._ 
    val now  = System.currentTimeMillis() // this is executed during compilation! 
    val nowExpr = c.Expr[Long](Literal(Constant(now))) 
    val code = reify(new Date(nowExpr.splice)) 
    c.Expr(code.tree) 
    } 
} 

Sử dụng macro (mã sau đây phải được biên soạn riêng từ mã vĩ mô ở trên):

object MacroTest extends App { 
    println(s"This project was compiled on ${CompileTime()}") 
} 

(Nếu bạn chạy nhiều lần, bạn thấy rằng thời gian biên dịch thực sự là không đổi)


Vì vậy, trong ngắn hạn, macro cung cấp chức năng là không phải có sẵn trong bất kỳ phiên bản Scala nào trước đây. Bạn có thể làm những việc với các macro mà bạn không thể làm khác (thường bạn có thể viết những thứ tương tự bằng cách sử dụng sự phản chiếu thời gian chạy, nhưng các macro được kiểm tra tại thời gian biên dịch).

Tuy nhiên, với tư cách là người dùng, bạn sẽ được tiếp xúc nhiều hơn với các thư viện kết hợp macro, vì chúng có thể cung cấp các cấu trúc mạnh mẽ và an toàn.Ví dụ, serialisers tự động cho JSON từ một lớp case có thể được thực hiện với macro, bởi vì macro có thể kiểm tra kiểu lớp case của bạn và xây dựng cấu trúc chương trình (AST) chính xác để đọc và viết lớp case đó, không có nguy cơ thời gian chạy thất bại.

Một số liên kết ngẫu nhiên

+1

Một số thư viện đăng nhập và tuần tự hóa sử dụng các macro phía sau hậu trường. – Andy