0
package scalaworld.macros
import scala.meta._

class Argument(arg: Int) extends scala.annotation.StaticAnnotation {
  inline def apply(defn: Any): Any = meta {
    println(this.structure)
    val arg = this match {
      // The argument needs to be a literal like `1` or a string like `"foobar"`.
      // You can't pass in a variable name.
      case q"new $_(${Lit(arg: Int)})"                      => arg
      // Example if you have more than one argument.
      case q"new $_(${Lit(arg: Int)}, ${Lit(foo: String)})" => arg
      case _                                                => ??? // default     value
    }
    println(s"Arg is $arg")
    defn.asInstanceOf[Stat]
  }
}

我想修改上面的宏并添加类型参数[A]。我尝试了以下但它没有编译

package scalaworld.macros
import scala.meta._

class Argument2[A](arg: A) extends scala.annotation.StaticAnnotation {
  inline def apply(defn: Any): Any = meta {
    println(this.structure)
    val arg = this match {
      case q"new $_(${Lit(arg: A)})"                      => arg
      case q"new $_(${Lit(arg: A)}, ${Lit(foo: String)})" => arg
      case _                                              => ???
    }
    println(s"Arg is $arg")
    defn.asInstanceOf[Stat]
  }
}
4

1 回答 1

1

传递给宏注释的参数作为元树传递。

尽管可以通过提取器提取诸如 Int/Double/String 之类的文字Lit()。其他情况并非如此。

在元中解析时

  • @someMacro(1)变成@someMacro(Lit(1))
  • @someMacro("Foo")变成@someMacro(Lit("Foo"))

其他一切都像往常一样通过

  • @someMacro(foo)变成@someMacro(Term.Name("foo"))
  • @someMacro(Option(2))变成@someMacro(Term.Apply(Term.Name("Option"), Seq(Lit(2))))

这意味着您没有对此事物的运行时访问权限。如果没有 Semantic Api 来解析符号等,您甚至无法正确实例化对象。这在 scalameta 2 和天堂 4 中可能是可能的,但现在肯定是不可能的。您可以做的是进行运行时模式匹配以检查该值。

我在这里做了一些类似的事情(注意这是非常 WIP): https://github.com/DavidDudson/Elysium/blob/master/gen/src/main/scala/nz/daved/elysium/gen/MacroAnnotation.scala

具体参见https://github.com/DavidDudson/Elysium/blob/master/gen/src/main/scala/nz/daved/elysium/gen/MacroAnnotation.scala#L149

注意:这意味着在运行时(在该示例中恰好是编译时),如果传入的 arg 类型不正确,则会出现运行时异常

于 2017-01-21T10:05:56.737 回答