/ / (Co) Wariancja na listach innych niż na stosach w Scali? - java, generics, scala, kowariancja

(Co) Wariancja na listach różni się od stosów w Scali? - java, generics, scala, covariance

Kiedy piszę ten kod, mam błąd kompilacji w Scali

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

Jest to równoważne kolekcji kowariantnej w Javie ze względu na symbol wieloznaczny; dokładnie wpisz nieznany, więc nie możemy dodać czegoś do stosu.

Ale z listami nie dostaję tego samego błędu:

   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

Teraz mogę dodać nawet float, ale tak naprawdę uwierzyłbym list jest List z Integers, zatem nie Floats dozwolony.

1) Dlaczego jest to dozwolone w przypadku list, a nie stosów? Czy to z powodu minusów (: :) operatora?

2) Jaki jest typ listy? Czy to jest dynamiczne?

3) Dlaczego jest to dozwolone w Scali, a nie w Javie?

4) Czy mogę dodać coś do stosu? (null nie działa, w Javie działa, ponieważ typy ogólne dopuszczają tylko typy referencyjne)

Odpowiedzi:

6 dla odpowiedzi № 1

:: nie jest mutacją. Oznacza to, że x :: xs zwróci listę typów List[ commonSupertypeOf[ typeOf[x], elementTypeOf[xs] ] ] (to nie jest rzeczywisty kod Scala, ale mam nadzieję, że mój punkt się pojawi), ale to nie zmieni typu xs. Gdyby xs ma typ List[Float] i x ma typ Integer, a następnie wyrażenie x :: xs będzie miał typ List[Numeric], ale rodzaj xs jest wciąż List[Float], więc nic się nie psuje.

add jest to jednak operacja mutacji. xs.add(x) doda Integer do a Stack którego typ jest Stack<Float>, co jest wyraźnie błędem.

To wyjaśnia, dlaczego to robisz x :: xs nie jest niebezpieczne. Teraz wyjaśnij, dlaczego tak się dzieje:

Singnature of :: na List[A] jest: def :: [B >: A] (x: B) : List[B].

Oznacza to, że dla każdego typu A i B gdzie B jest supertypem A, :: podana wartość typu B i listę typu A wyświetli listę typów B. Więc kiedy coś zrobisz someInteger :: someFloats, kompilator wnioskuje o tym B jest Numeric i A jest Float i wszystko działa.

W kategoriach java byłoby to <B supertypeOf A> List<B> prepend(B item) oprócz tego supertypeOf nie jest legalna java.


4 dla odpowiedzi nr 2

Język Scala używa wariancji strony definicjiadnotacje, a nie adnotacje wariancji witryny. Kowariancja dla list jest zdefiniowana w cechy listy, natomiast stosy nie są zdefiniowane jako kowariant. Ogólnie kolekcje zmienne żargon być kowariantną, ponieważ prowadzi to do błędów typu polegających na wstawianiu nowych elementów do kolekcji (co jest poważnym problemem w przypadku macierzy kowariantnych Java).