加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 将传递的函数体拼接成宏重写的表达式

发布时间:2020-12-16 08:58:41 所属栏目:安全 来源:网络整理
导读:我正在玩 Scala 2.11的新宏功能.我想看看我是否可以进行以下重写: forRange(0 to 10) { i = println(i) }// intoval iter = (0 to 10).iteratorwhile (iter.hasNext) { val i = iter.next println(i)} 我认为我对这个宏非常接近: def _forRange[A](c: Blac
我正在玩 Scala 2.11的新宏功能.我想看看我是否可以进行以下重写:

forRange(0 to 10) { i => println(i) }

// into

val iter = (0 to 10).iterator
while (iter.hasNext) {
  val i = iter.next
  println(i)
}

我认为我对这个宏非常接近:

def _forRange[A](c: BlackboxContext)(range: c.Expr[Range])(func: c.Expr[Int => A]): c.Expr[Unit] = {
  import c.universe._

  val tree = func.tree match {
    case q"($i: $t) => $body" => q"""
        val iter = ${range}.iterator
        while (iter.hasNext) {
          val $i = iter.next
          $body
        }
      """
    case _ => q""
  }

  c.Expr(tree)
}

当调用forRange(0到10)时,这会产生以下输出{i => println(i)}(至少,它是show函数在结果树上给我的东西):

{
  val iter = scala.this.Predef.intWrapper(0).to(10).iterator;
  while$1(){
    if (iter.hasNext)
      {
        {
          val i = iter.next;
          scala.this.Predef.println(i)
        };
        while$1()
      }
    else
      ()
  }
}

看起来它应该可以工作,但我手动定义的val i和拼接函数体中引用的i之间存在冲突.我收到以下错误:

ReplGlobal.abort: symbol value i does not exist in$line38.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw.
error: symbol value i does not exist in
scala.reflect.internal.FatalError: symbol value i does not exist in $line38.$read$$iw$$iw$$iw$$iw$$iw$$iw$$iw$$iw.

然后是一个相当大的堆栈跟踪,导致“被遗弃的崩溃会话”通知.

我无法判断这是否是我的逻辑问题(你根本无法在引用封闭变量的函数体中拼接),或者它是否是新实现的错误.错误报告肯定会更好.我在Repl上运行它可能会加剧这种情况.

是否可以拆分一个函数,将正文与封闭的术语分开,并重写它以便将逻辑直接拼接到结果树中?

解决方法

如有疑问,请重置AllAttrs:

import scala.language.experimental.macros
import scala.reflect.macros.BlackboxContext

def _forRange[A](c: BlackboxContext)(range: c.Expr[Range])(
  func: c.Expr[Int => A]
): c.Expr[Unit] = {
  import c.universe._

  val tree = func.tree match {
    case q"($i: $t) => $body" => q"""
        val iter = ${range}.iterator
        while (iter.hasNext) {
          val $i = iter.next
          ${c.resetAllAttrs(body)} // The only line I've changed.
        }
      """
    case _ => q""
  }

  c.Expr(tree)
}

然后:

scala> def forRange[A](range: Range)(func: Int => A) = macro _forRange[A]
defined term macro forRange: [A](range: Range)(func: Int => A)Unit

scala> forRange(0 to 10) { i => println(i) }
0
1
2
3
4
5
6
7
8
9
10

一般来说,当你从一个地方抓住一棵树并将其放在其他地方时,可能需要使用resetAllAttrs来获得所有符号.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读