首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么Foo[C]是Foo[B]的一个子类型?

为什么Foo[C]是Foo[B]的一个子类型?
EN

Stack Overflow用户
提问于 2017-04-28 07:27:46
回答 1查看 63关注 0票数 1

我试图理解差异,在我买的这本书中,它解释如下:

·无注释参数FooA的A型在A中是不变的,这意味着无论B和C之间的亚型或超型关系如何,FooB与FooC之间都没有关系。·参数FooB的A型在A中是逆变的,如果C是B的超型,则FooC是FooB的子型。

我很难理解这句话:

代码语言:javascript
复制
If C is a supertype of B, Foo[C] is a subtype of Foo[B].

为什么不:

代码语言:javascript
复制
Foo[C] is a supertype of Foo[B].

C是一个超级类型的B,但是为什么C突然变成了B的子型呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-28 09:04:45

C是一个超级类型的B,但是为什么C突然变成了B的子型呢?

这就是反向方差的定义,它逆转了关系顺序(在我们的例子中,是关系<:的"is子类型“)。注意,C现在不是B的子类型,关系是固定的,而是C的容器,即Foo[C],现在是BFoo[B],而不是直接B本身的容器的子类型。

反方差的典型例子是函数对象。Scala中的函数在参数类型中是反变体,在返回类型(即Function1[-T, +R] )中是协变函数。

让我们看看一个例子。假设我们有一个小ADT:

代码语言:javascript
复制
sealed trait Animal
case class Mouse() extends Animal
case class Lion() extends Animal

现在我们要从Lion => String创建一个函数。我们能从Animal => String中提供一个具体的功能吗?

代码语言:javascript
复制
def main(args: Array[String]): Unit = {
  val animalToString: (Animal) => String = an => an.toString
  val lionToString: (Lion) => String = animalToString

  lionToString(new Lion())
}

这为什么要编译呢?因为当您使用lionToString调用Lion时,您肯定知道它将能够调用在Animal上定义的任何函数,因为Lion <: Animal。但事实并非如此。假设Function1在其参数类型中是协变的:

代码语言:javascript
复制
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.
}

这样,当我们的函数实际需要一个Animal时,我们就可以传递一个不同的Lion子类型。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43674447

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档