如何在 Scala 宏中将 context.universe.Annotation 转换为 MyAnnotation

How to convert context.universe.Annotation to MyAnnotation in a Scala Macro

我使用的是 Scala 2.11.1,我有一个注解

case class MyAnnotation(id: String, message: String) extends StaticAnnotation

我想创建一个宏 MessageFromMyAnnotation 来转换以下代码

class Foo {
    @MyAnnotation("001", "James Bond 001")
    def foox = {
        ... // my messy code
        val x = MessageFromMyAnnotation("001")
        ... // my messy code
    }
}

class Foo {
    @MyAnnotation("001", "James Bond 001")
    def foox = {
        ... // my messy code
        val x = "Hello world, James Bond 001"
        ... // my messy code
    }
}

简而言之,宏在其封闭元素上找到 message of @MyAnnotationid = "001" 和 return "Hello world, " + message

这是宏

object MessageFromMyAnnotation {
    def apply(id: String) = macro impl
    def impl(c: Context)(id: c.Expr[String]): c.Expr[String] = {
        c.internal.enclosingOwner.annotations.filter( anno =>
          anno.tpe =:= c.universe.typeOf[MyAnnotation] &&
          anno.asInstanceOf[MyAnnotation].id == id.value //this does not work
        ) match {
            case anno :: Nil => c.universe.reify("Hello world, " + ...)
            case x => c.abort(c.enclosingPosition, c.universe.showRaw(x))
        }
    }
} 

我想将 cuniverse.Annotation 类型的 anno 转换为 MyAnnotation 并将其 idc.Expr[String] 类型的参数 id 进行比较,但是 anno.asInstanceOf[MyAnnotation] 产生 ClassCastException 并且 id.value 给我一条错误消息

cannot use value except for signatures of macro implementations

所以,请帮我解决两个问题:

感谢@Imm的建议,我已经成功了:

You don't have an instance of MyAnnotation - this is compile time, you only 
have an AST that represents the call. You can get the Expr that's the 
parameter given to the cuniverse.Annotation, and either splice it, or pattern 
match it as a String literal and then take the value out of that.

这是代码

object MessageFromMyAnnotation {
  def apply(id: String) = macro impl
  def impl(c: Context)(id: c.Expr[String]): c.Expr[String] = {
    import c.universe._
    id match { case Expr(Literal(Constant(idVal: String))) => 
      (for { Annotation(tpe, 
             Literal(Constant(annoIdVal: String)) :: 
             Literal(Constant(annoMessageVal: String)) :: 
             Nil, _) <- c.internal.enclosingOwner.annotations
             if tpe =:= typeOf[MyAnnotation] && idVal == annoIdVal
           } yield (annoIdVal, annoMessageVal)
      ) match {
        case (annoIdVal, annoMessageVal) :: Nil => 
          reify(c.literal("Hello world, " + annoMessageVal).splice)
        case matchedMore :: thanOne :: Nil => c.abort(c.enclosingPosition, "Found more than one @MyAnnotation with the same id")
        case x => c.abort(c.enclosingPosition, "Not Found @MyAnnotation with the specified id")
      }
    }
  }
}