Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从Scala宏注释获取参数_Scala_Annotations_Scala Macros - Fatal编程技术网

从Scala宏注释获取参数

从Scala宏注释获取参数,scala,annotations,scala-macros,Scala,Annotations,Scala Macros,所以我在函数(DefDef)上有一个注释。此注释具有参数。 但是,我对如何从构造函数中获取参数感到困惑 用法示例: class TestMacro { @Foo(true) def foo(): String = "" foo } 下面是注释的代码: class Foo(b: Boolean) extends StaticAnnotation { def macroTransform(annottees: Any*) = macro Foo.impl } object Foo

所以我在函数(DefDef)上有一个注释。此注释具有参数。 但是,我对如何从构造函数中获取参数感到困惑

用法示例:

class TestMacro {
  @Foo(true)
  def foo(): String = ""
  foo
}
下面是注释的代码:

class Foo(b: Boolean) extends StaticAnnotation {
  def macroTransform(annottees: Any*) = macro Foo.impl
}

object Foo {
  def impl(c: whitebox.Context)(annottees: c.Tree*): c.Expr[Any] = {
    import c.universe._
    //how do I get value of `b` here???
    c.abort(c.enclosingPosition, "message")
  }
}
那么这个呢:

val b: Boolean = c.prefix.tree match {
    case q"new Foo($b)" => c.eval[Boolean](c.Expr(b))
}
为了完整起见,这是完整的来源:

import scala.reflect.macros.Context
import scala.language.experimental.macros
import scala.annotation.StaticAnnotation
import scala.annotation.compileTimeOnly
import scala.reflect.api.Trees
import scala.reflect.runtime.universe._

class Foo(b: Boolean) extends StaticAnnotation {
  def macroTransform(annottees: Any*) :Any = macro FooMacro.impl
}

object FooMacro {
  def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._
    val b: Boolean = c.prefix.tree match {
        case q"new Foo($b)" => c.eval[Boolean](c.Expr(b))
    }
    c.abort(c.enclosingPosition, "message")
  }
}

如果您想使用具有可选命名参数的静态注释,这是一个显示Federico技术变体的答案。在这种情况下,您需要考虑案例匹配语句中可能的调用表达式。可选参数可以显式命名,也可以不命名,或者不存在。在编译时,它们中的每一个都作为一个单独的模式显示在
c.prefix.tree
中,如下所示

@compileTimeOnly("Must enable the Scala macro paradise compiler plugin to expand static annotations")
class noop(arg1: Int, arg2: Int = 0) extends StaticAnnotation {
  def macroTransform(annottees: Any*): Any = macro AnnotationMacros.noop
}

class AnnotationMacros(val c: whitebox.Context) {
  import c.universe._

  // an annotation that doesn't do anything:
  def noop(annottees: c.Expr[Any]*): c.Expr[Any] = {
    // cases for handling optional arguments
    val (arg1q, arg2q) = c.prefix.tree match {
      case q"new noop($arg1, arg2 = $arg2)" => (arg1, arg2)  // user gave named arg2
      case q"new noop($arg1, $arg2)" => (arg1, arg2)         // arg2 without name
      case q"new noop($arg1)" => (arg1, q"0")                // arg2 defaulted
      case _ => c.abort(c.enclosingPosition, "unexpected annotation pattern!")
    }

    // print out the values
    println(s"arg1= ${evalTree[Int](arg1q)}   arg2= ${evalTree[Int](arg2q)}")

    // just return the original annotee:
    annottees.length match {
      case 1 => c.Expr(q"{ ${annottees(0)} }")
      case _ => c.abort(c.enclosingPosition, "Only one annottee!")
    }
  }

  def evalTree[T](tree: Tree) = c.eval(c.Expr[T](c.untypecheck(tree.duplicate)))
}
下面是一个名为
arg2
的调用示例,因此它将匹配上面的第一个模式--
案例q“new noop($arg1,arg2=$arg2)”

object demo {
  // I will match this pattern: case q"new noop($arg1, arg2 = $arg2)"
  @noop(1, arg2 = 2)
  trait someDeclarationToAnnotate
}
还要注意,由于这些模式的工作方式,您必须在宏代码中显式地提供默认参数值,这很不幸有点粗糙,但最终计算的类对您不可用


作为一个实验,我试图通过调用
evalTree[scope.of.class.noop](c.prefix.tree)
来创建这个类,但是Scala编译器抛出了一个错误,因为它认为在注释宏代码中引用注释是非法的。

这个解决方案很有趣,但出于某种原因,它似乎“有问题”对我来说。另外,我希望
b
是布尔类型,而不是任何类型。就像有人可以说
@Foo(“AAA”)
并认为他们的代码将通过查看构造函数的签名来编译。而且,如果我决定添加更多的参数,它会变得更加混乱。但是这个解决方案是有效的,所以谢谢你!这段代码现在不编译。当您将参数的类型从Boolean更改为Any时,一切正常。错误消息是:
Null类型的表达式不符合隐式转换的条件