如何获取带类型case class的默认字段值并修复断言错误
问题
我有一个可获取类默认字段及其值列表的Scala 3宏,当尝试用它获取带类型参数的类的默认值时,抛出断言错误:
[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:435) [error] | at scala.quoted.runtime.impl.QuotesImpl$reflect$Ref$.apply(QuotesImpl.scala:434) [error] | at defaultParamsImpl(Decoder.scala:126)
错误发生在代码行:val mod = Ref(sym.companionModule),请问该如何修复?
修复方案
错误原因
带类型参数的类符号(比如MyClass[String]的符号)的companionModule会返回空符号(NoSymbol)——因为泛型类的伴生模块是绑定到原始的无类型参数类符号(MyClass)上的,而非带具体类型参数的实例符号。直接对空符号调用Ref会触发Scala宏运行时的断言失败。
具体修复步骤
获取原始无类型参数的类符号
先通过typeSymbol剥离类型参数,拿到原始类的符号,再获取它的伴生模块:val originalClassSym = sym.typeSymbol val companionModuleSym = originalClassSym.companionModule前置检查符号有效性
在创建Ref之前,必须判断伴生模块符号是否存在,避免空符号触发断言:if !companionModuleSym.exists then throw new IllegalArgumentException(s"类 ${Type.show[T]} 不存在伴生模块")适配泛型类的默认参数逻辑
如果默认参数依赖泛型类型,需要通过Quotes的类型工具解析实际类型参数,确保默认值的计算能正确关联上下文。
修复后代码示例
修改defaultParamsImpl中的关键逻辑:
def defaultParamsImpl[T: Type](using Quotes): Expr[List[(String, Any)]] = { import quotes.reflect.* val typeRepr = TypeRepr.of[T] val sym = typeRepr.typeSymbol // 获取原始类符号 val originalClassSym = sym.typeSymbol // 检查伴生模块是否存在 val companionModuleSym = originalClassSym.companionModule if !companionModuleSym.exists then throw new IllegalArgumentException(s"Type ${Type.show[T]} has no companion module") // 安全创建伴生模块引用 val mod = Ref(companionModuleSym) // 后续获取默认参数的原有逻辑... }
内容的提问来源于stack exchange,提问作者Denis Savitsky
相关产品推荐
相关产品推荐

