#scala #scala-3 #hlist #dotty #singleton-type
Вопрос:
Из дерева иерархии типов в scala
- пусть a:
Tuple2[Int,Int]
, я знаюTuple2[Int,Int]
, что простирается отProduct2[Int,Int]
; - пусть b:
1 *: 2 *: EmptyTuple
имеет типTuple
(уточненный какInt *: Int *: EmptyTuple
)
Они разных типов и не имеют никакого отношения к родителям. Единственное , что у них обоих есть Product
, — это то, что они оба исходят из Product
.
Но я могу назначить a
b
и наоборот, почему?
Ответ №1:
В Scala 3 Tuple1
Tuple22
типы … синтетически модифицируются компилятором для расширения *:
типов. То Tuple2[A, B]
есть модифицируется для расширения A *: B *: EmptyTuple
(что расширяет Tuple
).
Таким образом, вы можете назначить a Tuple2[Int, Int]
к a Int *: Int *: EmptyTuple
. Аналогично, возможно обратное, потому что a A *: ... EmptyTuple
будет рассматриваться как a TupleN
, когда это возможно (
Комментарии:
1. Нет никаких причин, кроме магии компилятора
Ответ №2:
Это разные типы, но это не значит, что они не связаны. 1 *: 2 *: EmptyTuple
является подтипом Tuple2[Int,Int]
, потому что одноэлементные литералы 1
и 2
являются подтипами Int
, а параметры типа 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]]
Комментарии:
1. Я не думаю , что @LinLee имеет в виду одноэлементный тип
1 *: 2 *: EmptyTuple
, я думаю, что он просто имеет в видуInt *: Int *: EmptyTuple
.2. @MichaelZajac да, на основе результата, который, скорее всего, и произошел, но если бы вы сравнивали
a:Tuple2[Int,Int]
сb:1 *: 2 *: EmptyTuple
этим, это было бы сравнение между типами, и в обоих случаях значения были бы одинаковыми