Scala 3中元组类型工作原理:为何无法匹配HList形式类型?
Scala 3元组与HList类型匹配失败的原因
问题背景
有人告知Scala 3的元组表现类似Scala 2中shapeless的HList,因此进行了如下简单实验:
val tuple = (1, "String", 1.1) val _: *:[Int, *:[String, Double]] = tuple // 无法通过编译 val _: *:[Double, *:[String, Int]] = tuple // 无法通过编译
根据HList的定义,上述两种类型匹配中至少有一种应该可行,但实际均失败,完整报错信息如下:
[Error] /home/peng/git/dottyspike/src/main/scala/com/tribbloids/spike/dotty/NewTuple.scala:15:42: Found: (tuple : (Int, String, Double)) Required: Int *: String *: Double Explanation =========== Tree: tuple I tried to show that (tuple : (Int, String, Double)) conforms to Int *: String *: Double but none of the attempts shown below succeeded: ==> (tuple : (Int, String, Double)) <: Int *: String *: Double class dotty.tools.dotc.core.Types$CachedTermRef class dotty.tools.dotc.core.Types$CachedAppliedType ==> (Int, String, Double) <: Int *: String *: Double class dotty.tools.dotc.core.Types$CachedAppliedType class dotty.tools.dotc.core.Types$CachedAppliedType ==> (String, Double) <: String *: Double class dotty.tools.dotc.core.Types$CachedAppliedType class dotty.tools.dotc.core.Types$CachedAppliedType ==> Double *: EmptyTuple.type <: Double class dotty.tools.dotc.core.Types$CachedAppliedType class dotty.tools.dotc.core.Types$CachedTypeRef = false The tests were made under the empty constraint [Error] /home/peng/git/dottyspike/src/main/scala/com/tribbloids/spike/dotty/NewTuple.scala:17:42: Found: (tuple : (Int, String, Double)) Required: Double *: String *: Int Explanation =========== Tree: tuple I tried to show that (tuple : (Int, String, Double)) conforms to Double *: String *: Int but none of the attempts shown below succeeded: ==> (tuple : (Int, String, Double)) <: Double *: String *: Int class dotty.tools.dotc.core.Types$CachedTermRef class dotty.tools.dotc.core.Types$CachedAppliedType ==> (Int, String, Double) <: Double *: String *: Int class dotty.tools.dotc.core.Types$CachedAppliedType class dotty.tools.dotc.core.Types$CachedAppliedType ==> Int <: Double class dotty.tools.dotc.core.Types$CachedTypeRef class dotty.tools.dotc.core.Types$CachedTypeRef = false The tests were made under the empty constraint two errors found
原因解析
1. 类型结构不完整
Scala 3的元组确实基于*:(Cons运算符)和EmptyTuple构建,(A, B, C)的等价底层类型是A *: B *: C *: EmptyTuple。但你写的*:[Int, *:[String, Double]]等价于Int *: String *: Double,缺少了末尾的*: EmptyTuple,和元组的完整类型不匹配,这是第一个匹配失败的核心原因。
2. 类型顺序严格匹配
第二个匹配尝试Double *: String *: Int是元组类型的完全反转,不管是Scala 3元组还是shapeless HList,都是严格有序的异构列表,元素类型的顺序是类型的一部分。(Int, String, Double)对应的HList类型只能是Int *: String *: Double *: EmptyTuple,反转后的类型和原类型完全不兼容,自然无法通过编译。
3. 正确的写法示例
如果要让类型匹配通过,需要写出完整的HList风格类型,或者直接使用元组的标准类型:
// 完整HList风格类型匹配 val _: Int *: String *: Double *: EmptyTuple = tuple // 编译通过 // 标准元组类型匹配 val _: (Int, String, Double) = tuple // 编译通过
内容的提问来源于stack exchange,提问作者tribbloid
相关产品推荐
相关产品推荐

