【问题标题】:Using freshName as a parameter without explicitly specifying type使用 freshName 作为参数而不显式指定类型
【发布时间】:2020-12-15 08:26:39
【问题描述】:

我正在尝试在以下宏中使用 freshName 作为参数名称:

我。

def test: Unit = macro implTst

def implTst(c: blackbox.Context): c.Expr[Unit] = {
  import c.universe._

  def withImplicitsM(exprs: List[c.Tree], expr: c.Tree): c.Tree =
    exprs match {
      case Nil =>
        expr
      case head :: tail =>
        //error here
        q"""$head.flatMap(implicit ${c.freshName()} => ${withImplicitsM(tail, expr)})"""

    }

  val exprsIo    = List(q"cats.effect.IO.apply(1)", q"cats.effect.IO.apply(2)")
  val resultTree = q"""println(${withImplicitsM(exprsIo, q"cats.effect.IO.apply(3)")}.unsafeRunSync())"""

  c.Expr[Unit](resultTree)
}

它抛出编译错误:

[error] Main.scala:25:9: exception during macro expansion: 
[error] java.lang.IllegalArgumentException: "fresh$macro$2" is not valid representation of a parameter, consider reformatting it into q"val $name: $T = $default" shape

二。

用硬编码标识符替换新名称使其工作:

def test: Unit = macro implTst

def implTst(c: blackbox.Context): c.Expr[Unit] = {
  import c.universe._

  def withImplicitsM(exprs: List[c.Tree], expr: c.Tree): c.Tree =
    exprs match {
      case Nil =>
        expr
      case head :: tail =>
        q"""$head.flatMap(implicit i => ${withImplicitsM(tail, expr)})"""

    }

  val exprsIo    = List(q"cats.effect.IO.apply(1)", q"cats.effect.IO.apply(2)")
  val resultTree = q"""println(${withImplicitsM(exprsIo, q"cats.effect.IO.apply(3)")}.unsafeRunSync())"""

  c.Expr[Unit](resultTree)
}

有没有办法在不明确指定参数类型的情况下使用implicit ${c.freshName()}

【问题讨论】:

    标签: scala metaprogramming scala-macros scala-quasiquotes


    【解决方案1】:

    解决方案:

    在参数定义中显式使用空类型。

    def withImplicitsM(exprs: List[c.Tree], expr: c.Tree): c.Tree =
      exprs match {
        case Nil =>
          expr
        case head :: tail =>
          val emptyType = tq""
          val v         = q"implicit val ${TermName(c.freshName())}: $emptyType"
          q"""$head.flatMap($v => ${withImplicitsM(tail, expr)})"""
    
      }
    

    我是怎么想出来的

    我解构了一个类似的flatMap 调用并查看了参数定义的样子:

      val flatmapExpression               = q"cats.effect.IO.apply(1).flatMap(implicit i => cats.effect.IO.apply(2))"
      val q"$foo($args)"                  = flatmapExpression
      val q"(..$params) => $body"         = args
      val q"$mods val $name: $tpt = $rhs" = params(0)
      println(mods)
      println(name)
      println(tpt)
      println(rhs)
    

    这是打印出来的:

    Modifiers(implicit <param>, , Map())
    i
    <type ?>
    <empty>
    

    注意 &lt;type ?&gt; 是一个空类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-26
      • 1970-01-01
      • 2023-01-19
      相关资源
      最近更新 更多