(Co)列表中的差异与Scala中的Stacks不同吗?

Jul*_*ian 3 java generics scala covariance

当我编写这段代码时,我在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
Run Code Online (Sandbox Code Playgroud)

由于通配符,这相当于Java中的协变集合; 它确切的类型在未知,所以我们不能添加东西到堆栈.

但是对于列表,我不会得到同样的错误:

   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
Run Code Online (Sandbox Code Playgroud)

现在,我可以添加甚至float,但事实上我相信list是List的Integers,所以不会Floats允许的.

1)为什么这个列表允许,而不是Stacks?这是由于cons(::)运算符吗?

2)列表的类型是什么?它是动态的吗?

3)为什么在Scala而不是Java中允许这样做?

4)我可以在堆栈中添加一些东西吗?(null在Java中不起作用,因为泛型类型只允许引用类型)

sep*_*p2k 6

::不是变异操作.这意味着x :: xs将返回一个List类型List[ commonSupertypeOf[ typeOf[x], elementTypeOf[xs] ] ](这不是实际的scala代码,但我希望我的观点能够实现),但它不会改变类型xs.如果xs有类型List[Float]并且x有类型Integer,那么表达式x :: xs将具有类型List[Numeric],但类型xs仍然是List[Float],因此没有任何中断.

add然而,这是一个变异操作.xs.add(x)将添加Integer到Stack其类型是Stack<Float>,这显然是一个错误.

这解释了为什么做事x :: xs并不危险.现在来解释为什么它出现了类型:

的singnature ::上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之外.