📜  Scala——协方差

📅  最后修改于: 2022-05-13 01:55:40.902000             🧑  作者: Mango

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