了解一般不变性、协方差和逆变性

Understanding Generic Invariance, Covariance and Contravariance

提问人:Matthew Layton 提问时间:9/27/2021 更新时间:10/26/2021 访问量:373

问:

泛型的差异一直让我感到困惑。以下规则是我被引导相信的:

  • 不变 T:只接受 T 的类型;仅此而已。
  • 协变 T:接受 T 的类型和派生自 T 的类型,但不小于 T
  • 逆变 T:接受 T 的类型和小于 T 的类型,但不派生自 T

鉴于以下代码示例,我猜这是错误的:

class Invariant<T>(value: T)
class Covariant<out T>(value: T)
class Contravariant<in T>(value: T)

open class A
open class B : A()
open class C : B()

class VarianceExample {
    val invariantA: Invariant<B> = Invariant(A()) // Error (as expected)
    val invariantB: Invariant<B> = Invariant(B()) // Okay (as expected)
    val invariantC: Invariant<B> = Invariant(C()) // Okay (wait, what!?)

    val covariantA: Covariant<B> = Covariant(A()) // Error (as expected)
    val covariantB: Covariant<B> = Covariant(B()) // Okay (as expected)
    val covariantC: Covariant<B> = Covariant(C()) // Okay (as expected)

    val contravariantA: Contravariant<B> = Contravariant(A()) // Okay (as expected)
    val contravariantB: Contravariant<B> = Contravariant(B()) // Okay (as expected)
    val contravariantC: Contravariant<B> = Contravariant(C()) // Okay (wait, what!?)
}

特别是。。。

  • val invariantC: Invariant<B> = Invariant(C())

为什么允许我通过?Invariant<B>C()

  • val contravariantC: Contravariant<B> = Contravariant(C())

为什么允许我通过?Contravariant<B>C()

泛型与 语言无关 的协方差 方 逆变

评论

0赞 Matt Timmermans 9/28/2021
您没有为构造函数调用提供类型参数,因此编译器可以推断出有效的内容。例如,当你说 时,你正在构造一个Invariant(C())Invariant<B>(C())
0赞 captain-yossarian from Ukraine 10/22/2021
检查此问题 stackoverflow.com/questions/66410115/...。我链接了几篇关于 *-variance 的有用文章
0赞 Robert Mikes 10/29/2021
这肯定不是一个与语言无关的问题,因为它被标记了。您正在用某种语言进行测试,以说明您的困惑。其他语言的行为可能有所不同。
0赞 Matthew Layton 10/29/2021
@RobertMikes,如果没有用语言编写的示例,您如何演示问题?仅供参考,这同样适用于 C#
1赞 Robert Mikes 11/8/2021
@MatthewLayton 这个问题在与语言无关的上下文中没有意义,因为答案必须是特定于语言的,每种语言都不同。打个比方,你可以问一个与人类语言无关的语法问题“如何把动词放在现在进行时”,这在英语(和其他一些语言)中是完全有意义的,但在许多其他语言中根本没有意义。在有意义的语言中,答案会大不相同。因此,您应该使用您感兴趣的特定语言来标记您的问题。

答: 暂无答案