gpt4 book ai didi

Scala 宏分配解构函数的参数

转载 作者:行者123 更新时间:2023-12-03 04:15:34 30 4
gpt4 key购买 nike

我目前正在使用宏,也许这不是一个好主意,但这是我的问题:

我有以下宏:

def using[A <: { def close(): Unit }, B](resource: A)(f: A => B) = macro usingImpl[A, B]

def usingImpl[A <: { def close(): Unit }, B](c: Context)(resource: c.Expr[A])(f: c.Expr[A => B]): c.Expr[B] = {

import c.universe._


f.tree match {
case Function(params, body) =>
//val ValDef(modifiers, name, tpt, _) = params.head
c.Expr[B](
Block(
List(
//ValDef(modifiers, name, tpt, resource.tree)
ValDef(params.head.symbol, resource.tree)
),
body
)
)

case _: Select =>
reify {
val res = resource.splice
try {
f.splice(res)
} finally {
res.close()
}
}
}
}

如果是Select,我只需调用该函数并关闭资源,就可以正常工作。但对于 Function 来说,我想将参数值分配给资源并调用主体。当我使用已弃用的 ValDef 创建器时,它需要一个 Symbol 和一个 Tree,一切正常。如果我使用注释外的 4-args 创建器,则会收到编译器错误,指出值 x$1 不在范围内。当我查看两个版本生成的代码时,它看起来完全相同:

Expr[Int]({
<synthetic> val x$1: Test.Foo = new Test.this.Foo();
x$1.bar.+(23)
})

是否有一种方法可以简单地使用 params.head 并分配一个值?感谢您的帮助!

编辑:

我这样调用宏:

object Test extends App {
import Macros._

class Foo {
def close() {}

def bar = 3
}

println(using(new Foo)(_.bar + 3))
}

正如我所说,如果我使用注释掉的版本,它会给我一个编译器错误,打印 AST 并在最后显示此消息:[error] 符号值 x$1 不存在于测试$delayedInit$body.apply

我使用的是 2.10.1。

最佳答案

啊,现在我可以重现你的错误了。任何时候你得到“这个条目似乎已经杀死了编译器”。消息并在堆栈跟踪中看到类似这样的行:

at scala.reflect.internal.SymbolTable.abort(SymbolTable.scala:49)

您的下一步应该是开始在 c.resetAllAttrs 中包装内容。老实说,我第一次无法重现您的错误的原因是因为我在复制和粘贴后将 block 中的 body 替换为 c.resetAllAttrs(body)你的代码,甚至不假思索。此时这只是一种条件反射。

例如参见 this little single abstract method class demo对于需要使用此技巧的地方的类似实例。

就您而言,如果我们有:

import scala.language.experimental.macros
import scala.reflect.macros.Context

object Macros {
def using[A <: { def close(): Unit }, B](resource: A)(f: A => B) =
macro usingImpl[A, B]

def usingImpl[A <: { def close(): Unit }, B](c: Context)
(resource: c.Expr[A])(f: c.Expr[A => B]): c.Expr[B] = {
import c.universe._

val expr = f.tree match {
case Function(ValDef(modifiers, name, tpt, _) :: Nil, body) =>
c.Expr[B](
Block(
ValDef(modifiers, name, tpt, resource.tree) :: Nil,
c.resetAllAttrs(body)
)
)

case _: Select => reify {
val res = resource.splice
try { f.splice(res) } finally { res.close() }
}
}

println(expr)
expr
}
}

编译您的测试代码时,我们将看到以下内容:

Expr[B]({
<synthetic> val x$1: $line3.$read.$iw.$iw.Test.Foo = new Test.this.Foo();
x$1.bar.$plus(3)
})

完全符合要求。

关于Scala 宏分配解构函数的参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16451060/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com