在Scala中使用协方差符号或通用边界时

时间:2010-09-08 00:01:53

标签: scala bounds variance type-bounds

在Scala中,可以使用泛型运算符(如+和 - )在泛型类型参数上定义方差。例如,List类型在标准库中是协变的。

class List[+A]

所以带有协变列表的函数可以像这样定义:

def foo[A](list : List[A])

也可以使用通用边界模拟方差。所以我们也可以写这个

def foo[A](list : List[_:< A])

当然这没有意义,因为list已经是协变的。但是对于不协变的类型也可以采用相同的技巧。 (如Stack)。当然,也可以从堆栈(聚合的继承)创建一个新的类型,这是协变的。

所以我的问题:

  1. 何时应使用通用边界进行方差?我们什么时候应该创建一个新的协变类型?
  2. 泛型边界只对方差有用,或者它们可以声明更多(语言概念)。
  3. 如果它们只对方差有用,那么边界只是为了与Java兼容吗?
  4. 提前thx:)

2 个答案:

答案 0 :(得分:14)

如果一个类型是自然协变或逆变的,你应该声明它。您的用户会感谢您的支持。由于Java,使用站点方差确实存在。更准确地说,诸如Array[T <: Number]之类的类型被视为存在类型的简写:

ArrayBuffer[T] forSome { type T <: Number }

存在类型在Scala中具有相当庞大的语法。这有点故意,因为我们不建议你多用它们。你什么时候需要一个存在主义类型?

  1. 使用通配符(例如List<? extends Number>
  2. )编写Java类型的模拟
  3. 编写Java原始类型的模拟,例如List
  4. 在Java中,原始类型和通配符类型并不完全相同,也不是与存在类型完全相同(即使我们知道它们不是什么,也很难准确地说明它们是什么)。但它们与实践中的存在性非常接近,因此Scala可以将它们映射到这种类型。

答案 1 :(得分:6)

  1. 当创建一个新的泛型类型时,比如说Foo [T],你应该努力确定该类型是协变的,逆变的还是不变的,并声明它为Foo [+ T],Foo [-T]或Foo [T]分别。不可否认,这可能有点困难。但是,每当她需要通过使用泛型边界来使用Foo时,它就会让Foo的用户自由地做出决定。简而言之:当方差是类型本身的属性时,更喜欢声明站点差异而不是呼叫站点方差。
  2. BTW,Martin Odersky,Lex Spoon和Bill Venners撰写的Scala编程书中有一些关于差异的很好的选择。请参见第19章类型参数化。