Scala 中列表的(共同)方差与堆栈的方差不同?
当我编写这段代码时,我在 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 中由于通配符而导致的协变集合;它的确切类型未知,因此我们无法向堆栈添加某些内容。
但对于列表,我不会得到同样的错误:
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 中却起作用,因为泛型类型只允许引用类型)
When I'm writing this code, I've got a Compile error in 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
This is equivalent to covariant collection in Java due the wildcard; it exact type in unknown, so we cannot added something to the stack.
But with lists I won't get the same error:
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
Now I can added even a float
, but in fact I would believe the list
is a List
of Integers
, so not Floats
allowed.
1) Why is this allowed with lists, and not with Stacks? Is this due to the cons (::) operator?
2) What is the type of list? Is it dynamic?
3) Why is this allowed in Scala and not in Java?
4) Can I add something to the stack? (null
is not working, in Java does because generic types only allows reference types)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
::
不是变异操作。这意味着x :: xs
将返回List[ commonSupertypeOf[ typeOf[x], elementTypeOf[xs] ] ]
类型的 List (这不是实际的 scala 代码,但我希望我的观点能够被理解),但它不会改变xs
的类型。如果xs
的类型为List[Float]
并且x
的类型为Integer
,则表达式x : : xs
将具有List[Numeric]
类型,但xs
的类型仍然是List[Float]
,因此不会中断。然而,
add
是一个变异操作。xs.add(x)
会将一个Integer
添加到类型为Stack
的Stack
中,其中显然是一个错误。这解释了为什么执行
x :: xs
并不危险。现在解释为什么它会进行类型检查:List[A]
上的::
的签名是:def :: [B >: A] (x: B) : 列表[B]
。这意味着对于任何类型
A
和B
,其中B
是A
的超类型,::
给定B
类型的值和A
类型的列表将生成B
类型的列表。因此,当您执行某些someInteger :: someFloats
操作时,编译器会推断B
是Numeric
并且A
是浮动
,一切正常。用java术语来说,这将是
列表 prepend(B item)
,但supertypeOf
不是合法的 java.::
isn't a mutating operation. This means thatx :: xs
will return a List of typeList[ commonSupertypeOf[ typeOf[x], elementTypeOf[xs] ] ]
(this isn't actual scala code, but I hope my point comes across), but it will not change the type ofxs
. Ifxs
has typeList[Float]
andx
has typeInteger
, then the expressionx :: xs
will have typeList[Numeric]
, but the type ofxs
is stillList[Float]
, so nothing breaks.add
however is a mutating operation.xs.add(x)
will add anInteger
to aStack
whose type isStack<Float>
, which is clearly an error.This explains why doing
x :: xs
is not dangerous. Now to explain why it typeckecks:The singnature of
::
on aList[A]
is:def :: [B >: A] (x: B) : List[B]
.What this means is that for any types
A
andB
whereB
is a supertype ofA
,::
given a value of typeB
and a list of typeA
will produce a list of typeB
. So when you do somesomeInteger :: someFloats
, the compiler infers thatB
isNumeric
andA
isFloat
and everything works.In java terms that would be
<B supertypeOf A> List<B> prepend(B item)
except thatsupertypeOf
isn't legal java.Scala 语言使用定义站点差异注释,而不是使用站点差异注释。列表的协方差在列表特征中定义,而堆栈未定义为协变。一般来说,可变集合不能是协变的,因为这会导致涉及向集合插入新元素的类型错误(这是 Java 协变数组的一个主要问题。)
The Scala language uses definition-site variance annotations, not use-site variance annotations. Covariance for Lists is defined in the List trait, while Stacks are not defined as covariant. In general, mutable collections can't be covariant, because that leads to type errors involving inserting new elements into the collection (which is a major problem with Java's covariant arrays.)