Scala 协方差和下类型界解释

2024-02-13

我正在尝试了解使用下界创建新的不可变类型的方法的协方差

class ImmutableArray[+T](item: T, existing: List[T] = Nil) {  
  private val items = item :: existing

  def append[S >: T](value: S) = new ImmutableArray[S](value, items)
}

我理解类型参数T不能在追加方法中使用,因为它违反了规则,但如果我说Customer类和子类Student我仍然可以制作类型U Student.

我可以看到这是可行的,但为什么这不违反规则?如果我有一份清单,我就能理解Students,然后添加一个Customer我只能返回一个列表Customer由于不允许Customer被分配给一个Student因为它是父类型。但为什么我可以使用Student?

我缺少什么?

谢谢布莱尔


你的班级提供了 2 个涉及 T 的操作:

  1. 建造

    nextImmutableArray = new ImmutableArray(nextT, priorImmutableArray)
    

    由于此操作,类型参数 T 必须是协变的:+T。这允许您使用设置为类型(T 或 T 的子类型)的对象的参数来构造。

    思考:通过包含一个来构造一个 Oranges 数组是有效的Valencia Orange.

  2. 组合

    nextImmutableArray.append(newItemTorAncestor)
    

    此方法不会附加到您的数据结构。它需要两个独立的元素(您的数组实例this和一个额外的对象)和它combines它们位于新构造的数组中。您可以考虑将方法名称更改为追加到复制。更好的是,你可以使用这个名字+。但为了最正确且符合 Scala 约定,最好的名称是:+ .

    当你问一个具体问题时,为什么我对“随机”方法名称胡言乱语???

    因为该方法的精确性质决定了返回的数据结构是否 (a) 与 T 不变 (b) 与 T 共变 (c) 与 T 逆变。

    • 开头:ImmutableArray[T] - 包含类型 T (或子类型)
    • 结合:S 类型的对象。
    • 结果:ImmutableArray[S]
    • 如果允许 S 成为 T 的真子类型(超出 T 本身),则新数组不能包含类型 T 的原始元素!
    • 如果 S 是 T 类型或 T 的超类型,那么一切都很好 - 可以包含原始元素,加上新元素!

    当你combine数组和元素,新创建的数据结构必须具有一个类型参数,该类型参数是共同祖先类型的超类型。否则它不能包含原始元素。一般来说,当执行“a :+ b”时,其中 A 是 Array[A],b 是 B 类型,生成的数据结构是 Array[Some_SuperType_Of_Both_A_and_B]。

    想一想:如果我从一系列橙子开始,然后添加一个柠檬,我最终会得到一系列柑橘类水果(不是橙子、脐橙,也不是柠檬)。


方法规则(严格输入,宽松输出):

  • a) 输入参数提供一个要插入的元素(突变):共变体
  • a) 输出参数从数据结构返回一个元素:反变体
  • c) 输出参数,合并后返回数据结构:反变体
  • c) 使用类型作为下限:“翻转”方差(“T 的逆变”=“S 的协变,其具有下限 T”)

在追加的情况下:从 T 开始,输出数据结构 = T 的逆变,类型 S 使用 T 作为下限,因此输入参数 = 与 S 的协变。这意味着如果 T1 是 T2 的子类型,则ImmutableArray[T1] 是 ImmutableArray[T2] 的子类型,它可以是取代的无论何时需要后者,所有方法都遵循里氏替换原则。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Scala 协方差和下类型界解释 的相关文章

随机推荐