2013-06-21 30 views
10

Nhờ câu trả lời cho my previous question, tôi có thể tạo macro chức năng sao cho nó trả về một Map ánh xạ từng tên trường tới giá trị của một lớp, ví dụ:Scala Macros: Kiểm tra chú thích nhất định

... 

trait Model 

case class User (name: String, age: Int, posts: List[String]) extends Model { 
    val numPosts: Int = posts.length 

    ... 

    def foo = "bar" 

    ... 
} 

Vì vậy, lệnh này

val myUser = User("Foo", 25, List("Lorem", "Ipsum")) 

myUser.asMap 

lợi nhuận

Map("name" -> "Foo", "age" -> 25, "posts" -> List("Lorem", "Ipsum"), "numPosts" -> 2) 

Đây là nơi Tuple s cho Map được tạo ra (xem Travis Brown answer):

... 

val pairs = weakTypeOf[T].declarations.collect { 
    case m: MethodSymbol if m.isAccessor => 
    val name = c.literal(m.name.decoded) 
    val value = c.Expr(Select(model, m.name)) 
    reify(name.splice -> value.splice).tree 
} 

... 

Bây giờ tôi muốn bỏ qua các trường có chú thích @transient. Làm cách nào để kiểm tra xem phương thức có chú thích @transient không?

Tôi đang nghĩ đến việc thay đổi đoạn mã trên như

val pairs = weakTypeOf[T].declarations.collect { 
    case m: MethodSymbol if m.isAccessor && !m.annotations.exists(???) => 
     val name = c.literal(m.name.decoded) 
     val value = c.Expr(Select(model, m.name)) 
     reify(name.splice -> value.splice).tree 
} 

nhưng tôi không thể tìm thấy những gì tôi cần phải viết trong exists phần. Làm thế nào tôi có thể nhận được @transient làm Annotation để tôi có thể chuyển nó ở đó?

Cảm ơn trước!

Trả lời

11

Chú thích sẽ nằm trên chính trang val, không phải trên trình truy cập. Cách đơn giản nhất để truy cập val là thông qua việc accessed phương pháp trên MethodSymbol:

def isTransient(m: MethodSymbol) = m.accessed.annotations.exists(
    _.tpe =:= typeOf[scala.transient] 
) 

Bây giờ bạn chỉ có thể viết như sau trong bạn collect:

case m: MethodSymbol if m.isAccessor && !isTransient(m) => 

Lưu ý rằng phiên bản của isTransient tôi đã đưa ở đây phải được xác định trong macro của bạn, vì nó cần nhập từ c.universe, nhưng bạn có thể xác định nó bằng cách thêm đối số Universe nếu bạn đang thực hiện loại điều này trong một số macro.

+1

Cảm ơn bạn lần nữa! Tôi dường như không thể nhận được chú thích. Tôi đã thêm '@ transient' trước' name' và 'numPosts' trong lớp ví dụ ở trên, nhưng chúng vẫn được thêm vào bản đồ. Kỳ lạ là không có phương pháp nào được thực hiện thông qua 'isTransient' dường như có bất kỳ chú thích nào có sẵn. Cả hai 'm.accessed.annotations' và' m.annotations' đều trống. – Emre

+1

Điều đó rất kỳ quặc — nó làm việc cho tôi như mong đợi trong cả hai trường hợp. Bạn có thể đăng mã chính xác của mình không? –

+0

Đây là [code] (http://pastebin.com/PmW5qg3P). Lưu ý rằng tôi đang xây dựng một cái gì đó hơi khác nhau ở đây - một bản đồ của tất cả các lĩnh vực và các loại trường của các lớp trường hợp theo một gói nhất định. Vấn đề không có WeakTypeTag phải không? Cảm ơn trước. – Emre

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