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

如何获取带类型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宏运行时的断言失败。

具体修复步骤

  1. 获取原始无类型参数的类符号
    先通过typeSymbol剥离类型参数,拿到原始类的符号,再获取它的伴生模块:

    val originalClassSym = sym.typeSymbol
    val companionModuleSym = originalClassSym.companionModule
    
  2. 前置检查符号有效性
    在创建Ref之前,必须判断伴生模块符号是否存在,避免空符号触发断言:

    if !companionModuleSym.exists then
      throw new IllegalArgumentException(s"类 ${Type.show[T]} 不存在伴生模块")
    
  3. 适配泛型类的默认参数逻辑
    如果默认参数依赖泛型类型,需要通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 02:39:09