(Co) Разница в списках отличается от стеков в Scala? - PullRequest
3 голосов
/ 07 сентября 2010

Когда я пишу этот код, у меня появляется ошибка компиляции в Scala

var s: Stack[_ <: Number] = new Stack[Integer]; 
s.push(new Integer(1)); //compile-error: type mismatch; found :Integer required: _$bqjyh where type _$bqjyh <: Number
s.push(null); //compile-error: type mismatch; found   : Null(null) required: _$2 where type _$2 <: Objects.Vehicle

Это эквивалентно ковариантному сбору в Java из-за подстановочного знака;он точно указан в unknown, поэтому мы не можем добавить что-либо в стек.

Но со списками я не получу ту же ошибку:

   var list: List[_ <: Number] = Nil;
   var intList : List[Integer] = new Integer(1) :: Nil;
   list = intList ; //no error
   list = new Float(2) :: vehicles;  //even float allowed

Теперь я могу добавить даже float, но на самом деле я считаю, что list - это List из Integers, поэтому Floats не разрешено.

1) Почему это допускается со списками, а не со стеками?Это связано с оператором cons (: :)?

2) Какой тип списка?Это динамично?

3) Почему это разрешено в Scala, а не в Java?

4) Можно ли что-нибудь добавить в стек?(null не работает, в Java - потому что универсальные типы допускают только ссылочные типы)

Ответы [ 2 ]

6 голосов
/ 07 сентября 2010

:: не является мутантной операцией. Это означает, что x :: xs вернет список типа List[ commonSupertypeOf[ typeOf[x], elementTypeOf[xs] ] ] (это не настоящий скала-код, но я надеюсь, что моя точка зрения найдется), но это не изменит тип xs. Если xs имеет тип List[Float], а x имеет тип Integer, то выражение x :: xs будет иметь тип List[Numeric], но тип xs по-прежнему List[Float], поэтому ничего не нарушается.

add однако, является мутантной операцией. xs.add(x) добавит Integer к Stack, типом которого является Stack<Float>, что явно является ошибкой.

Это объясняет, почему выполнение x :: xs не опасно. Теперь, чтобы объяснить, почему он печатает:

Характерная особенность :: на List[A]: def :: [B >: A] (x: B) : List[B].

Это означает, что для любых типов A и B, где B является супертипом A, ::, если задано значение типа B, а список типа A будет составить список типа B. Поэтому, когда вы делаете someInteger :: someFloats, компилятор делает вывод, что B равно Numeric, а A равно Float и все работает.

В терминах Java это будет <B supertypeOf A> List<B> prepend(B item), за исключением того, что supertypeOf не является законным Java.

4 голосов
/ 07 сентября 2010

В языке Scala используются аннотации на основе определения сайта, а не аннотации на сайте.Ковариантность для списков определяется в признаке списка, а стеки не определяются как ковариантные.В общем случае изменяемые коллекции не могут быть ковариантными, поскольку это приводит к ошибкам типов, связанным с вставкой новых элементов в коллекцию (что является основной проблемой для ковариантных массивов Java.)

...