我有这个:
def myMacroImpl[T:Type](t: Expr[T])(using quotes:Quotes): Expr[String] = {
def fooFn(): Expr[(Any,StringBuilder) => StringBuilder] =
// quotes visible here
val qq = Expr(quotes) //wrap quotes in Expr to access inside Expr below
‘{(a:Any, sb:StringBuilder) =>
implicit val qt:Quotes = $qq
// use qt here for something that needs a Quotes instance, for ex reflection
sb.apply(“ok”)
}
}
当我尝试编译它时,我得到类似这样的东西,来自我实际调用顶级宏的地方:
[error] 16 | println(co.blocke.scala_reflection.ZType.myMacro(person))
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error] |Exception occurred while executing macro expansion.
[error] |java.lang.AssertionError: assertion failed
[error] | at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:11)
[error] | at scala.quoted.runtime.impl.QuotesImpl$reflect$Ref$.apply(QuotesImpl.scala:444)
[error] | at scala.quoted.runtime.impl.QuotesImpl$reflect$Ref$.apply(QuotesImpl.scala:443)
[error] | at co.blocke.scala_reflection.ZType$given_ToExpr_Quotes$.apply(ZType.scala:32)
[error] | at co.blocke.scala_reflection.ZType$given_ToExpr_Quotes$.apply(ZType.scala:30)
[error] | at scala.quoted.Expr$.apply(Expr.scala:37)
[error] | at co.blocke.scala_reflection.ZType$.fooFn$1(ZType.scala:76)
[error] | at co.blocke.scala_reflection.ZType$.myMacroImpl(ZType.scala:121)
Quotes 没有 Expr 转换器,所以我添加了这个:
given ToExpr[Quotes] with {
def apply(x: Quotes)(using q:Quotes) = {
import q.reflect._
Ref(defn.AnyClass).appliedToType(TypeRepr.typeConstructorOf(x.getClass)).asExpr.asInstanceOf[Expr[Quotes]]
}
}
我的直觉告诉我,我正在以艰难的方式做这件事——而且它显然不起作用,但我不知道答案。如何让 Quotes 实例可见/“传递到”我的 '{} 块?
将
Quotes
传递到引用中的唯一方法是:
// using quotes: Quotes
'{
val a = sth
someRuntimeMethod(
${ someCompileTimeMethod('{ a })(using quotes) }
)
}
您可以将
${}
放入 '{}
内,反之亦然。你做不到的是
// using quotes: Quotes
'{
someCompileTimeMethod(using quotes) // quotes from outside of '{}
}
因为它必须生成运行时代码,该代码期望值仅在编译期间可用(并且仅在此上下文中有效!)。
对于某些类型(通常是基元),您将拥有
given ToExpr[A]
,它允许您将 A
值转换为 Expr[A]
并在 '{}
中使用它(基本上让您在某个值中定义一个宏,然后使用它在引用的代码中),但 Quotes
不是这种类型。即使您手动构造了一些 ToExpr[Quotes]
的值,它几乎肯定会被破坏。
因此,要么在
${}
中使用 '{}
,要么在 inline def
中编写对 '{}
方法的调用,以便编译器创建一个新的嵌套 Quote
并将其传递给您。