Scala 中列表的(共同)方差与堆栈的方差不同?

发布于 2024-09-18 00:29:44 字数 999 浏览 8 评论 0原文

当我编写这段代码时,我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小糖芽 2024-09-25 00:29:44

:: 不是变异操作。这意味着 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 添加到类型为 StackStack 中,其中显然是一个错误。

这解释了为什么执行 x :: xs 并不危险。现在解释为什么它会进行类型检查:

List[A] 上的 :: 的签名是: def :: [B >: A] (x: B) : 列表[B]

这意味着对于任何类型 AB,其中 BA 的超类型,:: 给定 B 类型的值和 A 类型的列表将生成 B 类型的列表。因此,当您执行某些 someInteger :: someFloats 操作时,编译器会推断 BNumeric 并且 A浮动,一切正常。

用java术语来说,这将是 列表 prepend(B item) ,但 supertypeOf 不是合法的 java.

:: isn't a mutating operation. This means that x :: xs will return a List of type List[ 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 of xs. If xs has type List[Float] and x has type Integer, then the expression x :: xs will have type List[Numeric], but the type of xs is still List[Float], so nothing breaks.

add however is a mutating operation. xs.add(x) will add an Integer to a Stack whose type is Stack<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 a List[A] is: def :: [B >: A] (x: B) : List[B].

What this means is that for any types A and B where B is a supertype of A, :: given a value of type B and a list of type A will produce a list of type B. So when you do some someInteger :: someFloats, the compiler infers that B is Numeric and A is Float and everything works.

In java terms that would be <B supertypeOf A> List<B> prepend(B item) except that supertypeOf isn't legal java.

赠佳期 2024-09-25 00:29:44

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文