首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将参数传递给scalameta天堂宏

将参数传递给scalameta天堂宏
EN

Stack Overflow用户
提问于 2017-12-25 15:50:16
回答 1查看 360关注 0票数 0

我正在尝试创建一个宏注释,但我需要传递它的参数。

代码语言:javascript
复制
class ToPojo(param1: String, param2: String) extends StaticAnnotation {
  inline def apply(defn: Any): Any = meta {
        ...
  }
}

它被用作

代码语言:javascript
复制
@ToPojo("p1", "p2")
case class Entity(a: Int, m: Map[Long, Boolean])

上面的代码的问题是,随着注释被去掉,Entity就会像defn一样到达apply --因此我无法从那里获取参数。而且,param1param2字段不能从apply方法中访问,因为它是内联的。

您能告诉我使用scala克服这个问题的最简单方法吗?我想用两个注解

代码语言:javascript
复制
@ToPojo
@ToPojoParams("p1", "p2")
case class Entity(a: Int, m: Map[Long, Boolean])

但那又讨厌又丑。

非常感谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-12-26 04:40:06

正如ScalaMeta天堂描述中在如何将参数传递给宏注释?小节中所描述的那样

this上匹配为Scalameta树

代码语言:javascript
复制
package scalaworld.macros

import scala.meta._

class Argument(arg: Int) extends scala.annotation.StaticAnnotation {
  inline def apply(defn: Any): Any = meta {
    // `this` is a scala.meta tree.
    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.Int(arg)})" => arg
      // Example if you have more than one argument.
      case q"new $_(${Lit.Int(arg)}, ${Lit.String(foo)})" => arg
      case _ => ??? // default value
    }
    println(s"Arg is $arg")
    defn.asInstanceOf[Stat]
  }
}   

请注意,这段代码有点幼稚,不处理命名参数。如果你有很多的论点,写所有可能的组合通常和命名的参数是无聊的。所以你可以试试这样的方法:

代码语言:javascript
复制
package examples

import scala.collection.immutable
import scala.meta._

class MyMacro(p1: String, p2: Int) extends scala.annotation.StaticAnnotation {


  inline def apply(defn: Any): Any = meta {
    val params = Params.extractParams(this)
    //some implementation
    ... 
  }

}


case class Params(p1: String, p2: Int) {
  def update(name: String, value: Any): Params = name match {
    case "p1" => copy(p1 = value.asInstanceOf[String])
    case "p2" => copy(p2 = value.asInstanceOf[Int])
    case _ => ???
  }
}

object Params {
  private val paramsNames = List("p1", "p2")

  def extractParams(tree: Stat): Params = {
    val args: immutable.Seq[Term.Arg] = tree.asInstanceOf[Term.New].templ.parents.head.asInstanceOf[Term.Apply].args

    args.zipWithIndex.foldLeft(Params(null, 0))((acc, argAndIndex) => argAndIndex._1 match {
      case q"${Lit(value)}" => acc.update(paramsNames(argAndIndex._2), value)
      case q"${Term.Arg.Named(name, Lit(value))}" => acc.update(name.value, value)
    })
  }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47970102

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档