将TupleN值赋给*:type变量在Scala3中是如何工作的



从scala 中的类型层次结构树

  • 设a:Tuple2[Int,Int],我知道Tuple2[Int,Int]是从Product2[Int,Int]延伸而来的
  • 设b:1 *: 2 *: EmptyTuple具有类型Tuple(细化为Int *: Int *: EmptyTuple)

它们是不同的类型,没有任何父关系。它们都只有Product,它们都是从Product扩展而来的。

但我可以将a分配给b,反之亦然,为什么?

在Scala 3中,Tuple1。。。编译器对CCD_ 12类型进行了综合修改,扩展了CCD_。也就是说,Tuple2[A, B]被修改为扩展A *: B *: EmptyTuple(它扩展了Tuple)。

因此,可以将Tuple2[Int, Int]分配给Int *: Int *: EmptyTuple。同样,相反的情况也是可能的,因为A *: ... EmptyTuple将被视为TupleN(<=22类型参数)。

它们是不同的类型,但这并不意味着它们不相关。1 *: 2 *: EmptyTupleTuple2[Int,Int]的亚型,因为单例文字12Int的亚型并且Tuple2的类型参数是协变的。

可以将1 *: 2 *: EmptyTuple的实例扩展为Tuple2[Int,Int],但不能反过来。

请注意,Tuple2[A, B]A *: B *: EmptyTuple是等效的。基于问题的语法,假设1 *: 2 *: EmptyTuple是类型级表达式,但如果它是值级表达式,则它的类型将是Int *: Int *: EmptyTuple,相当于Tuple2[Int,Int]。在这种情况下,两种类型的实例都是";可分配的";彼此之间。

参考代码:

@main def main() =
type T1 = Tuple2[Int, Int]
type T2 = 1 *: 2 *: EmptyTuple
val t1a: T1 = (1, 2) //compiles
val t2a: T2 = (1, 2) //compiles
val t1b: T1 = (2, 1) //compiles
//  val t2b: T2 = (2, 1) // does not compile
//  t1a: T2 //does not compile
t2a: T1 //compiles
summon[1 <:< Int] // compiles
//  summon[1 =:= Int] // does not compile
summon[T2 <:< T1] //compiles
//  summon[T1 <:< T2] // does not compile
//  summon[T1 =:= T2] // does not compile
//these are the same types, not exclusively subtypes of one another
summon[Tuple2[Int, Int] =:= Int *: Int *: EmptyTuple]
summon[Tuple2[Int, Int] <:< Int *: Int *: EmptyTuple]
summon[Int *: Int *: EmptyTuple <:< Tuple2[Int, Int]]

最新更新