Почему Array [T forSome {type T; }] означает Массив [Любой]

Я читаю статью "Экзистенциальные типы в Scala" и нашел то, что я не могу понять:

Array[T] forSome { type T; }
Array[T forSome { type T; }]

Они выглядят почти одинаковыми, но на самом деле они очень разные. Первый - это тип всех массивов, независимо от их параметра типа. Второй - это Array [Any].

Почему они такие разные, и особенно, почему второй означает Array[Any]?

Ответ 1

Разница заключается в том, когда система типов решает, что такое T.

Возможно, лучший ответ: попробуйте использовать эти два типа в каком-то коде, посмотрите, что происходит, и попытайтесь выяснить, почему. Но сначала я попытаюсь объяснить теорию некоторых типов. В этом случае:

Array[T forSome { type T; }]

где forSome находится внутри скобок [], каждый элемент сам по себе просто должен быть как-то объяснен как T forSome { type T; }. ОК, поэтому Int является T для некоторого типа T, поэтому вы можете поместить Int в массив. A String также является T для некоторого типа T, и поскольку выбор forSome применяется только к одному элементу за раз, вы можете сказать T is String на этот раз вместо Int, поэтому вы можете поместить String в массив, хотя он уже содержит Int.

С другой стороны, хотя мы можем выбрать T независимо для любого элемента массива, уже выбран тип самого массива: это тип массива, который может удерживать что угодно. Это не может быть Array[Int] или Array[String].

Но в этом случае:

Array[T] forSome { type T; }

тип T определяется только один раз, вне массива. На самом деле массив может быть Array[Int] и Array[String], или Array[Any]. Но как только выбран тип T, все элементы массива должны быть совместимы с этим типом.

ОК, теперь попробуйте код. Вот пример:

scala> var a = Array(1,2);
a: Array[Int] = Array(1, 2)

scala> def first(z : Array[T] forSome { type T }) = z(0);
first: (z: Array[_])Any

scala> def firstany(z : Array[T forSome { type T }]) = z(0);
firstany: (z: Array[T forSome { type T }])Any

scala> first(a);
res0: Any = 1

scala> firstany(a);
error: type mismatch;
 found   : Array[Int]
 required: Array[T forSome { type T }]
       firstany(a);
                ^

Почему ошибка? Поскольку массив a имеет тип Array[Int], который может содержать только вещи типа Int. Это, безусловно, Array[T] forSome {type T}, потому что все системы типов нужно делать, это выбрать Int как тип T. Поэтому first(a) в порядке. Но, как объяснялось выше, Array[T forSome { type T }] не может быть Array[Int], поэтому firstany(a) является ошибкой.

Но все в порядке, потому что Array[Any] - это Array[T forSome { type T }]:

scala> var b = Array(1, "x");
b: Array[Any] = Array(1, x)

scala> firstany(b);
res1: Any = 1

Ответ 2

Не удивительно, что изменение позиций скобок может сильно изменить смысл. Немного нравится, если вы переключаетесь и существуете; и & theall;

Первый означает: существует такой тип T, что это Array[T]. Таким образом, это выполняется Array[String], Array[Int] и т.д. Массив однородный, но мы не знаем, на каком типе.

Второй означает: для каждого элемента массива существует некоторый тип T, так что элемент имеет тип T. Это не ограничение, так что это просто Array[Any]. Наличие forSome внутри квадратных скобок может быть полезно, если вы делаете, например,

Array[Set[T] forSome {type T}]

Это означает, что элементом массива являются все Sets, но в этом же массиве может быть как набор Int, так и набор строк.


Относительно комментария Rich Oliver о стирании стилей: это, в основном, время компиляции, и они действительно разные. В первом случае это массив, тип элемента которого мы не знаем. Поэтому мы не можем сделать, например, a(0) = 1, потому что это может быть Array[String]. Напротив, со вторым типом это Array[Any], а a (0) = 1 - ok.