泛型类
泛型类是将类型当作参数的类,此机制只要用于集合类。
1 定义泛型类
泛型类将类型作为参数放入方括号中[]。虽然任意名称可以作为参数,但一般使用字母A作为类型参数标识符。
class Stack[A] {
private var elements: List[A] = Nil
def push(x: A) { elements = x :: elements }
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
elements = elements.tail
currentTop
}
}
note:elements = x :: elements使用新创建的列表给elements赋值,新列表通过将x添加到当前elements之前创建。
2 用法
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop)
println(stack.pop)
如果类型参数具有子类型,这些子类型都可以被传入。
class Fruit
class Apple extends Fruit
class Banana extends Fruit
val sta= new Stack[Fruit]
val apple = new Apple
val banana = new Banana
sta.push(apple)
sta.push(banana)
泛型的子类型是不变的,这意味着如果有一个字符类型的栈Stack[Char],他不能用作整数类型栈Stack[Int]。这是不合理的,这会导致将真正的整数输入字符栈中。最后,只有当B=A时,Stack[A]才是Stack[B]的子类型。由于这可能过分严格,所以Scala提供了类型参数注解机制来控制泛型的子类型行为。
变化
变化是复杂类型的子类关系之间的关联以及它们的组件类型的子类型关系之间的关联。Scala支持范型类的类型参数的变化注解以允许它们在没有使用注解的情况下,是协变的、逆变的或不变的。在类型系统中使用变化可以在复杂类型间建立直观的连接,而缺少变化可以限制类抽象的复用。
class Foo[+A] // A covariant class
class Bar[-A] // A contravariant class
class Baz[A] // An invariant class
1 协变性(covariance)
通过使用注解+A,可以令泛型类的类型参数A设置为协变。对于class List[+A],令类型参数A为协变意味着,对于类型X与Y,其中X为Y的子类型,List[X]便是List[Y]的子类型。
2 逆变性(contravariance)
通过使用注解-A,可以将泛型类的类型参数A设置为逆变。对于class Writer[-A],令类型参数A为逆变意味着,对于类型X与Y,其中X是Y的子类型,则Writer[Y]是Write[X]的子类型。
3 不变性(invariance)
Scala中的泛型类默认为不变。这意味着,既不是协变也不是逆变。对于class Container[A],令类型参数A为不变,意味着对于类型X与Y,其中X是Y的子类型,但是Container[X]与Container[Y]之间没有关系。
4 与其他语言比较
一些类似Scala的语言以不同的方式支持变化。例如,Scala的变化注解类似于C#中在定义抽象类时添加的注解。Java中,当抽象类被使用时,由客户端指定变化注解。