Scala3嵌套样例类提取扁平化元组及Tuple.fromProductTyped报错修复
错误原因
Tuple.fromProductTyped 是编译期方法,依赖入参具体类型的 deriving.Mirror.ProductOf 隐式实例。你原来的写法中,模式匹配拿到的 x 静态类型是 Product,编译器无法为抽象的 Product 类型找到对应的隐式Mirror实例,因此报错。当你硬编码为Baz("hello")时,编译器知道静态类型是Baz,能自动生成对应的Mirror实例,所以运行正常。
解决方案
我们可以用Scala 3的类型类派生机制,在编译期完成嵌套结构的扁平化,避免运行时类型擦除带来的隐式找不到问题:
import deriving.Mirror // 定义扁平化类型类:将类型T转换为扁平化元组Out trait Flattener[T]: type Out <: Tuple def apply(t: T): Out object Flattener: // 辅助类型别名,方便直接获取扁平化后的元组类型 type Aux[T, O <: Tuple] = Flattener[T] { type Out = O } // 基础类型实例:非Product类型直接包装为单元素元组 given [T <: Matchable](using T <:< Not[Product]): Aux[T, T *: EmptyTuple] = new Flattener[T]: type Out = T *: EmptyTuple def apply(t: T): Out = t *: EmptyTuple // 空元组实例 given Aux[EmptyTuple, EmptyTuple] = new Flattener[EmptyTuple]: type Out = EmptyTuple def apply(t: EmptyTuple): Out = EmptyTuple // 非空元组实例:递归扁平化头部和尾部,再拼接 given [H, T <: Tuple, HF <: Tuple, TF <: Tuple]( using hf: Aux[H, HF], tf: Aux[T, TF] ): Aux[H *: T, Tuple.Concat[HF, TF]] = new Flattener[H *: T]: type Out = Tuple.Concat[HF, TF] def apply(t: H *: T): Out = hf(t.head) ++ tf(t.tail) // 样例类(Product)实例:先转成对应元组,再递归扁平化 given [P <: Product, M <: Tuple]( using m: Mirror.ProductOf[P] { type MirroredElemTypes = M }, f: Aux[M, ?] ): Aux[P, f.Out] = new Flattener[P]: type Out = f.Out def apply(p: P): Out = f(Tuple.fromProductTyped(p)) // 对外暴露的扁平化方法 def flatTuple[T](t: T)(using f: Flattener[T]): f.Out = f(t) // 测试代码 case class Baz(x: String) case class Employee(name: Baz, number: Int, manager: Boolean) @main def run() = val res = flatTuple(Employee(Baz("hello"), 42, false)) println(res) // 输出:(hello,42,false)
补充说明
如果你需要和原来的代码一样,先转成第一层元组再扁平化,也可以直接调用flatTuple处理第一层元组,效果完全一致:
val tuple = Tuple.fromProductTyped(Employee(Baz("hello"), 42, false)) println(flatTuple(tuple)) // 同样输出(hello,42,false)
内容的提问来源于stack exchange,提问作者gekomad
相关产品推荐
相关产品推荐

