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).