You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala 3宏中如何将Quotes实例传入Expr代码块?

问题分析与解决方案

核心问题本质

Quotes是Scala 3宏编译期专属的上下文实例,它仅存在于宏展开阶段,无法被序列化为Expr嵌入到生成的运行时代码中——运行时根本不存在这个实例,因此你尝试传递Quotes到生成代码的思路从根源上不可行,自定义的ToExpr[Quotes]也只会生成无效的引用,触发断言错误。

正确解决思路

拆分编译期逻辑和运行时逻辑:

  • 所有依赖Quotes的反射操作,必须在宏展开阶段(即myMacroImpl或fooFn内部)完成,将计算结果以普通值(如字符串、常量)的形式传入生成的代码。
  • 如果确实需要在运行时做类型反射,改用Scala的运行时反射API(scala-reflect库),而非宏的Quotes上下文。

方案1:提前完成编译期计算

假设你原本想在生成的函数里用Quotes做类型反射,可将反射逻辑提前到宏展开阶段完成,把结果传入运行时代码:

import scala.quoted.*

def myMacroImpl[T: Type](t: Expr[T])(using quotes: Quotes): Expr[String] = {
  import quotes.reflect._

  // 编译期用Quotes完成反射计算:获取T的类型名称
  val typeName = TypeRepr.of[T].typeSymbol.name.toString

  def fooFn(): Expr[(Any, StringBuilder) => StringBuilder] = {
    val typeNameExpr = Expr(typeName)
    '{(a: Any, sb: StringBuilder) =>
      // 直接使用编译期计算好的结果,无需Quotes
      sb.append("Target type: ").append($typeNameExpr)
    }
  }

  val foo = fooFn()
  '{
    val sb = new StringBuilder()
    $foo($t, sb).toString()
  }
}

方案2:改用运行时反射(如需运行时动态处理类型)

如果必须在运行时做动态反射操作,添加scala-reflect依赖后使用运行时API:

// build.sbt中添加依赖
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value

宏实现代码:

import scala.quoted.*

def myMacroImpl[T: Type](t: Expr[T])(using quotes: Quotes): Expr[String] = {
  def fooFn(): Expr[(Any, StringBuilder) => StringBuilder] = {
    '{(a: Any, sb: StringBuilder) =>
      // 使用运行时反射API,无需编译期Quotes
      import scala.reflect.runtime.universe._
      val mirror = runtimeMirror(getClass.getClassLoader)
      val runtimeType = mirror.classSymbol(a.getClass).toType
      sb.append("Runtime type: ").append(runtimeType.toString)
    }
  }

  val foo = fooFn()
  '{
    val sb = new StringBuilder()
    $foo($t, sb).toString()
  }
}

为什么原有方案失败?

  1. Quotes是编译器在宏展开时临时创建的上下文对象,没有对应的运行时实例,无法被转化为Expr。
  2. 你自定义的ToExpr[Quotes]试图创建一个指向编译期对象的引用,但这个引用在运行时无有效对象对应,直接触发断言错误。

内容的提问来源于stack exchange,提问作者Greg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 18:55:25