2015-04-18 12 views
5

Tôi khá mới đối với Scala và rất mới viết macro và tìm kiếm một chút trợ giúp/tư vấn. Tôi có mã sau đây ...Scala Tree Match Case

trait ValidationRule 
case class Required() extends ValidationRule 
case class HasLength(l: Int) extends ValidationRule 
case class Person(name: String) 

myMacro[Person] { p => p.name.is(Required(), HasLength(255)) } 

Rõ ràng có một số mã bị thiếu ở đây nhưng đây chỉ là giả để đưa ra câu hỏi.

Vì vậy, hãy cho một cây đại diện cho p => p.name.is(Required(), HasLength(255)) Tôi đang cố viết match/case để chọn tất cả các biểu thức đại diện cho một ValidationRule. Một cái gì đó như:

case TypeApply(Select(_, .... 

bất cứ ai có thể đề xuất các trường hợp phù hợp nhất để có thể trích xuất một danh sách của cây đại diện cho mỗi "tất cả" ValidationRules từ bên trong "là" phương pháp?

+0

Bạn có chắc chắn bạn cần macro ở đây không? Bạn có thể giải thích phương thức 'is' của bạn đến từ đâu không? –

+0

Có, tôi khá chắc chắn tôi muốn macro, phương thức "is" lấy ValidationRules và macro tìm tất cả các lần xuất hiện để tạo đối tượng chứa "tên" của thuộc tính đang được thử nghiệm cộng với giá trị và tất cả các quy tắc để chạy nó. Không thực sự tìm cách tranh luận nếu cách tiếp cận của tôi là cách tốt nhất ... tìm kiếm trợ giúp với trường hợp sử dụng cụ thể để làm các trường hợp phù hợp trong macro để tìm tất cả ValidateRules trong biểu thức. – user2270883

Trả lời

2

Bạn nên chắc chắn xem xét Quasiquotes.

Quasiquotes được sử dụng để làm hai việc: để xây dựng cây cối, và để phù hợp với mô hình cây. Chúng cho phép bạn thể hiện cây mà bạn muốn làm việc với mã Scala tương đương. Bạn để cho thư viện quasiquote đối phó với cách mã Scala ánh xạ tới một biểu đồ Tree, và đó là một điều tốt!

Bạn có thể chơi xung quanh với họ trong REPL, mặc dù kết quả có thể hơi khác nhau trong vũ trụ vĩ mô:

scala> import scala.reflect.runtime.universe._ 
scala> showRaw(cq"p => p.name.is(Required(), HasLength(255))") 

res0: String = CaseDef(
    Bind(
    TermName("p"), 
    Ident(termNames.WILDCARD)), 
    EmptyTree, 
    Apply(
    Select(
     Select(
     Ident(TermName("p")), 
     TermName("name")), 
     TermName("is")), 
    List(
     Apply(
     Ident(TermName("Required")), 
     List()), 
     Apply(
     Ident(TermName("HasLength")), 
     List(Literal(Constant(255))))))) 

Một điều khác bạn có thể làm với Quasiquotes là để thực sự sử dụng chúng để phù hợp với mô hình.

Bây giờ, bạn phải cẩn thận, vì mẫu đó CHỈ phù hợp nếu người dùng đặt tên biến mẫu p.

scala> val fromTree = cq"x => x.name.is(Required(), HasLength(255))" 
scala> val cq"p => p.name.is($x, $y)" = fromTree 

scala.MatchError: case (x @ _) => x.name.is(Required(), HasLength(255)) (of class scala.reflect.internal.Trees$CaseDef) 
    ... 33 elided 

Thay vào đó, bạn sẽ muốn có một chút chung chung hơn:

scala> val cq"${p1:TermName} => ${p2:TermName}.name.is($x, $y)" = fromTree 
p1: reflect.runtime.universe.TermName = x 
p2: reflect.runtime.universe.TermName = x 
x: reflect.runtime.universe.Tree = Required() 
y: reflect.runtime.universe.Tree = HasLength(255) 

scala> p1 == p2 
res2: Boolean = true 

Và, tất nhiên, nếu bạn đã làm điều này như là một phần của một mô hình phù hợp, bạn có thể làm:

case cq"${p1:TermName} => ${p2:TermName}.name.is($x, $y)" if p1 == p2 => 
    ??? 

Hãy nhớ rằng Macro là lỗ sâu, sâu. Nếu bạn chỉ mới bắt đầu, hãy dành nhiều thời gian để nhận mã macro của bạn chính xác. Sau đó, hy vọng sẽ dành rất nhiều thời gian đối phó với các trường hợp cạnh.

+0

Cảm ơn Daniel, phản ứng tuyệt vời và điều đó giúp ích cho bạn. Quasiquotes trông giống như một cách hay để học/sử dụng và hiểu cách phân tích một cây. – user2270883

+0

Làm thế nào để "case cq" (ví dụ sau) thay đổi nếu phương thức "is" lấy N số ValidationRules? Vì vậy, nói cách khác chữ ký phương thức "là" trông như thế này? def là (quy tắc: ValidationRule *) Tôi có thể sử dụng QUASIQUOTES như thế nào trong trường hợp đó? – user2270883

+1

Tôi nghĩ rằng tôi nhanh chóng tìm ra chính nó, nó sẽ trông như thế này: trường hợp cq "$ {p1: TermName} => $ {p2: TermName} .name.is (.. $ x)" nếu p1 == p2 => "x" nào sẽ cung cấp cho bạn danh sách ValidationRules. – user2270883

Các vấn đề liên quan