为什么 Foo[C] 是 Foo[B] 的子类型?
Contravariant why Foo[C] is a subtype of Foo[B]?
我试图理解方差,在我买的书中解释如下:
• A type with an unannotated parameter Foo[A] is invariant in A. This
means there is no relationship between Foo[B] and Foo[C] no matter
what the sub- or super-type relationship is between B and C.
• A type with a parameter Foo[+A] is covariant in A. If C is a
subtype of B, Foo[C] is a subtype of Foo[B].
• A type with a parameter Foo[-A] is contravariant in A. If C is a
supertype of B, Foo[C] is a subtype of Foo[B].
我很难理解这句话:
If C is a supertype of B, Foo[C] is a subtype of Foo[B].
为什么不呢:
Foo[C] is a supertype of Foo[B].
C
是超类型 B
但为什么 C
突然变成 B
的子类型?
C
is a supertype B
but why C
change suddenly to subtype of B
in
contravariant?
这是逆变的定义,它反转关系顺序(在我们的例子中,"is subtype of"关系<:
)。
请注意,并不是 C
现在是 B
的子类型,这种关系是固定的,它是 是 [=13= 的容器的东西],即 Foo[C]
,现在是 B
、Foo[B]
容器的子类型,而不是直接 B
本身。
逆变的经典例子是函数对象。 Scala 中的函数在参数类型上是逆变的,在 return 类型上是协变的,即 Function1[-T, +R]
.
让我们看一个例子。假设我们有一个小的 ADT:
sealed trait Animal
case class Mouse() extends Animal
case class Lion() extends Animal
现在我们要从 Lion => String
创建一个函数。我们可以给它一个来自 Animal => String
的具体函数吗?
def main(args: Array[String]): Unit = {
val animalToString: (Animal) => String = an => an.toString
val lionToString: (Lion) => String = animalToString
lionToString(new Lion())
}
为什么编译?因为当你用 Lion
调用 lionToString
时,你肯定知道它将能够调用在 Animal
上定义的任何函数,因为 Lion <: Animal
。但反之则不然。假设 Function1
在其参数类型上是协变的:
def main(args: Array[String]): Unit = {
val lionToString: (Lion) => String = an => an.toString
val animalToString: (Animal) => String = lionToString
lionToString(new Mouse()) // <-- This would blow up.
}
然后当我们的函数实际需要 Lion
.
时,我们就可以传递 Animal
的不同子类型
我试图理解方差,在我买的书中解释如下:
• A type with an unannotated parameter Foo[A] is invariant in A. This means there is no relationship between Foo[B] and Foo[C] no matter what the sub- or super-type relationship is between B and C.
• A type with a parameter Foo[+A] is covariant in A. If C is a subtype of B, Foo[C] is a subtype of Foo[B].
• A type with a parameter Foo[-A] is contravariant in A. If C is a supertype of B, Foo[C] is a subtype of Foo[B].
我很难理解这句话:
If C is a supertype of B, Foo[C] is a subtype of Foo[B].
为什么不呢:
Foo[C] is a supertype of Foo[B].
C
是超类型 B
但为什么 C
突然变成 B
的子类型?
C
is a supertypeB
but whyC
change suddenly to subtype ofB
in contravariant?
这是逆变的定义,它反转关系顺序(在我们的例子中,"is subtype of"关系<:
)。
请注意,并不是 C
现在是 B
的子类型,这种关系是固定的,它是 是 [=13= 的容器的东西],即 Foo[C]
,现在是 B
、Foo[B]
容器的子类型,而不是直接 B
本身。
逆变的经典例子是函数对象。 Scala 中的函数在参数类型上是逆变的,在 return 类型上是协变的,即 Function1[-T, +R]
.
让我们看一个例子。假设我们有一个小的 ADT:
sealed trait Animal
case class Mouse() extends Animal
case class Lion() extends Animal
现在我们要从 Lion => String
创建一个函数。我们可以给它一个来自 Animal => String
的具体函数吗?
def main(args: Array[String]): Unit = {
val animalToString: (Animal) => String = an => an.toString
val lionToString: (Lion) => String = animalToString
lionToString(new Lion())
}
为什么编译?因为当你用 Lion
调用 lionToString
时,你肯定知道它将能够调用在 Animal
上定义的任何函数,因为 Lion <: Animal
。但反之则不然。假设 Function1
在其参数类型上是协变的:
def main(args: Array[String]): Unit = {
val lionToString: (Lion) => String = an => an.toString
val animalToString: (Animal) => String = lionToString
lionToString(new Mouse()) // <-- This would blow up.
}
然后当我们的函数实际需要 Lion
.
Animal
的不同子类型