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

Scala 3.6.4:如何在引用表达式中调用带类型边界的多态方法

解决Scala 3宏中调用类型类方法时的子类型约束问题

问题原因

你遇到的报错是因为宏上下文里,编译器无法自动推导headType是A的子类型——尽管我们知道Sum类型的MirroredElemTypes中的每个元素必然是A的子类型,但宏的类型检查器不会自动识别这个隐含关系,必须显式提供证据。

解决方案

可以通过两种方式解决:

方法1:显式提供子类型证据

利用Type的<:<关系,在调用getFor时带上隐式的子类型证据,让编译器认可headType <: A:

def deriveSerializerImpl[A: Type](using quotes: Quotes): Expr[Serializer[A]] = {
    import quotes.reflect.*
    Expr.summon[Mirror.Of[A]] match {
        case Some('{ $m: Mirror.SumOf[A] {type MirroredElemTypes = elemTypes} }) =>
            Type.of[elemTypes] match {
                case '[headType *: tailTypes] =>
                    val discriminatorCriteriaExpr = Expr.summon[DiscriminatorCriteria[A]].get
                    // 显式获取headType <:< A的证据
                    val subTypeEvidence = Expr.summon[headType <:< A].get
                    // 调用时带上证据,让编译器确认子类型约束
                    val discriminator: Expr[Int] = '{ 
                        given _: headType <:< A = $subTypeEvidence
                        $discriminatorCriteriaExpr.getFor[headType] 
                    }
                    // 补充后续返回Expr[Serializer[A]]的逻辑,示例占位
                    '{ Serializer.make($discriminator) }
            }
        case _ => // 处理非Sum类型的情况
            ???
    }
}

方法2:直接强制类型转换(简洁但需谨慎)

如果确定headType必然是A的子类型,可以直接用Type.asInstanceOf强制转换类型参数,绕过编译器检查:

def deriveSerializerImpl[A: Type](using quotes: Quotes): Expr[Serializer[A]] = {
    import quotes.reflect.*
    Expr.summon[Mirror.Of[A]] match {
        case Some('{ $m: Mirror.SumOf[A] {type MirroredElemTypes = elemTypes} }) =>
            Type.of[elemTypes] match {
                case '[headType *: tailTypes] =>
                    val discriminatorCriteriaExpr = Expr.summon[DiscriminatorCriteria[A]].get
                    // 强制将headType转换为A的子类型
                    val headTypeAsSubtype = Type.of[headType].asInstanceOf[Type { type T <: A }]
                    val discriminator: Expr[Int] = '{ 
                        $discriminatorCriteriaExpr.getFor[${Type.show[headTypeAsSubtype.T]}] 
                    }
                    '{ Serializer.make($discriminator) }
            }
        case _ => ???
    }
}

补充说明

第一种方法更安全,通过隐式证据让编译器验证子类型关系;第二种方法更简洁,但依赖你对Sum类型结构的确定性,适合能保证headType一定是A子类型的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 04:37:12