Scala协方差与下界类型解释 [英] Scala Covariance and Lower Type Bounds Explanation
问题描述
我试图使用下界来创建新的不可变类型的方法,让我的头在协方差方面
类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
不能在append方法中使用,因为它违反了规则,但是如果我有一个 Customer
类和子类学生
我仍然可以使类型 U
学生
。
我可以看到这个作品,但为什么这不违反规则?我可以理解,如果我有学生
s的列表,然后添加客户
我只能返回<由于不允许将客户
分配给学生$ c $>,因此code> Customer
因为它是父类型。但为什么我可以使用学生
?
我缺少什么?
感谢布莱尔
您的课程提供2个涉及T的操作:
-
构造
nextImmutableArray = new ImmutableArray(nextT,priorImmutableArray)
由于这种操作,类型参数T必须是协变式:+ T。这允许您使用参数集来构造一个类型为(T或T的子类型)的对象。
想一想:通过添加一个 Valencia Orange来构建橙子数组是有效的。
-
组合
nextImmutableArray.append(newItemTorAncestor)
code>此方法不会附加到您的数据结构。它需要两个独立的元素(数组实例 this 和一个额外的对象),并将它们结合在一个新构建的数组中。您可以考虑将您的方法名称更改为 appendIntoCopy 。更好的是,您可以使用名称 + 。但为了最好地正确和符合Scala惯例,最好的名字应该是:+ 。
为什么我会在一个'随机'因为该方法的确切性质决定了返回的数据结构是否是(a)T(b)与T(c)逆变换与T的非变量。
- 开始于:ImmutableArray [T] - 包含类型T(或子类型)
- 与S类型的对象结合使用。
- 结果:ImmutableArray [S]
- 如果S被允许是T的适当子类型(超出T本身),那么新数组不能包含原始T型元素!
- 如果S的类型是T或T的超类型,那么一切都很好 - 可以包含原始元素和新元素!
结合数组和元素时,新创建的数据结构必须具有一个类型参数共同的祖先类型的超类型。否则,它不能包含原始元素。通常,当您执行a:+ b时,其中A是数组[A],而b是类型B,则生成的数据结构是数组[Some_SuperType_Of_Both_A_and_B]。
想一想:如果我从一组桔子开始,然后添加一个柠檬,我最终会得到一串柑橘类水果 (不是橘子,脐橙,也不是柠檬)。
b - a)输入参数提供了一个元素来插入(突变): Co-Variant
- a)输出参数数据结构: Contra-Variant
- c)输出参数,在合并后返回数据结构: Contra-Variant < c)使用类型作为下界:翻转方差(对T的反变换=对S的同变异,具有下界T)
Construction
nextImmutableArray = new ImmutableArray(nextT, priorImmutableArray)
Because of this operation, the type parameter T must be co-variant: +T. That allows you to construct with the parameter set to an object of type (T OR a subtype of T).
Think: it's valid to construct an array of Oranges by including a Valencia Orange.
Combination
nextImmutableArray.append(newItemTorAncestor)
This method doesn't append to your data structure. It takes two independent elements (your array instance this and an extra object) and it combines them within a newly constructed array. You could consider changing your method name to appendIntoCopy. Even better, you could use the name +. But to be most correct and consistent with Scala conventions, the best name would be :+ .
Why am I waffling on about a 'random' method name, when you asked a specific question???
Because precise nature of the method determines whether the returned data structure is (a) non-variant with T (b) co-variant with T (c) contra-variant with T.
- Start with: ImmutableArray[T] - contains type T (or subtypes)
- Combine with: Object of type S.
- Result: ImmutableArray[S]
- If S was allowed to be a proper subtype of T (beyond T itself), then the new array can't contain original elements of type T!
- If S is of type T or a supertype of T, then all is good - can contain original elements, plus new element!
When you combine arrays and elements, the newly created data structure must have a type parameter that is a supertype of the common ancestor type. Otherwise it couldn't contain the original elements. In general when you carry out "a :+ b", where A is an Array[A] and b is of type B, the resulting data structure is Array[Some_SuperType_Of_Both_A_and_B].
Think: if I start with an array of Oranges, then add a Lemon, I end up with an array of Citrus Fruit (not Oranges, Navel Oranges, nor Lemons).
- a) input parameter provides an element to insert (mutation): Co-Variant
- a) output parameter returns an element from data structure: Contra-Variant
- c) output parameter, returns data structure after combining: Contra-Variant
- c) Use type as a lower bound: "Flip" variance ("Contra-variant to T" = "Co-Variant to S, which has lower-bound T")
$ b 方法规则(严格的输入,容纳输出):
如果追加:从T开始,输出数据结构= S使用T作为下界,所以输入参数=与S.T的同变异他的意思是,如果T1是T2的一个子类型,则ImmutableArray [T1]是ImmutableArray [T2]的子类型,并且可以在任何后者被预期的情况下替换,所有方法都遵循Liskov的替换原则。
I am trying to get my head around covariance in respect with methods creating new immutable types using lower bounds
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)
}
I understand that the type parameter T
can not be used in the append method as it violates the rules but if I have say a Customer
class and sub class Student
I can still make the type U
Student
.
I can see this works but why is this not a violation of the rules? I could understand if I had a list of Student
s and then added a Customer
I could only return a list of Customer
s due to not allowing a Customer
to be assigned to a Student
as it is a parent type. But why can I use Student
?
What am I missing?
Thanks Blair
Your class offers 2 operations involving T:
Method Rules (strict on input, accomodating on output):
In case of append: Start with T, Output Data Structure = Contra-Variant to T, Type S uses T as a lower-bound, so Input Parameter = Co-Variant with S. This means that if T1 is a subtype of T2 then ImmutableArray[T1] is a subtype of ImmutableArray[T2] and that it can be substituted wherever the latter is expected, with all methods following Liskov's substitution principle.
这篇关于Scala协方差与下界类型解释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!