Scala——协方差
方差是子类型关系的互连,这些关系既可以是复杂类型,也可以是其组成类型。 Scala 提供了三种类型的方差:
- 协变
- 逆变的
- 不变的
协方差表明,如果有两个参数化类型使得 S 是 T 的子类型,则 List[S] 是 List[T] 的子类型。这是一种继承关系。所以,这基本上定义了我们是否可以用它的基类型替换一个类型的关系。简单地说,如果我们举一个例子,其中 Car 是 Vehicle 的子类型,那么 List[Car] 是 List[Vehicle] 的子类型。因此,我们可以将 List[Car] 替换为 List[Vehicle]。当我们声明一个类型是协变的,那么它在不同位置的安全使用就会受到限制。在不可变类型的情况下,协方差被广泛使用。
句法:
List[+T]
这里,T 是一个类型参数,“+”符号代表 Scala 协方差。
让我们借助示例来讨论这个概念:
示例 1:
// Scala program to illustrate the concept of covariance
// Creating an abstract class
// for Flower
abstract class Flower
{
def name: String
}
// Creating a sub-class Lily
// of Flower
case class Lily(name: String) extends Flower
// Creating a sub-class Carnation
// of Flower
case class Carnation(name: String) extends Flower
object Covariance extends App
{
// Creating a method
def FlowerNames(flowers: List[Flower]): Unit =
{
flowers.foreach
{
flower => println(flower.name)
}
}
// Assigning names
val lily: List[Lily] = List(Lily("White Lily"),
Lily("Jersey Lily"))
val carnations: List[Carnation] = List(Carnation("White carnations"),
Carnation("Pink carnations"))
// Print: names of lily
FlowerNames(lily)
// Print: names of carnation
FlowerNames(carnations)
}
输出:
White Lily
Jersey Lily
White carnations
Pink carnations
解释:在上面的例子中,百合和康乃馨是花的子类型。因此,很明显 List[Lily] 是 List[Flower] 并且 List[Carnation] 也是 List[Flower],我们可以将它们中的任何一个替换为 List[Flower]。在代码的后面部分,有一个方法 FlowerNames 打印鲜花的名称,可接受的参数是鲜花列表。如果这两个列表是协变的,那么只有方法调用才会编译并且花名会被分别打印出来。因此,由于 Lily 和 Carnation 是 Flowers 的子类型,最后两行将由于协方差而执行。
笔记:
- 这里使用抽象类来应用协变,因为它具有 List[+T] ,其中类型参数 T 是协变的。
- 这里使用了一个 trait App 来快速将对象转换为可操作的程序。
示例 2:
// Scala program to illustrate the concept of covariance
// Creating an abstract class
// for Animal
abstract class Animal
{
def name: String
}
// Creating a sub-class Mammal
// of Animal
case class Mammal(name: String) extends Animal
// Creating a sub-class Reptile
// of Animal
case class Reptile(name: String) extends Animal
object CovarianceExample extends App
{
// Creating a method
def SpecieNames(animals: List[Animal]): Unit =
{
animals.foreach
{
animal =>println(animal.name)
}
}
// Assigning names
val mammals: List[Mammal] = List(Mammal("Zebra"),
Mammal("Horse"))
val reptiles: List[Reptile] = List(Reptile("Snake"),
Reptile("Lizard"))
// Print: names of mammals
SpecieNames(mammals)
// Print : names of reptiles
SpecieNames(reptiles)
}
输出:
Zebra
Horse
Snake
Lizard