问题描述
考虑以下事项:
trait AA {
def children: List[AA]
}
trait BB {
def children: List[BB]
}
class CC extends AA,BB {
override def children: List[AA] & List[BB] = ???
}
当我们在 children
中覆盖 CC
时,覆盖的方法是顶级方法的合并实体。因此返回类型 List[AA] & List[BB]
是有意义的。
我不明白的是,下面是如何编译的?
class DD extends AA,BB {
override def children: List[AA & BB] = ???
}
List 是协变的,因此(这里是 proof 的来源):
List[AA & BB] <: List[AA] & List[BB]
DD
只能在 also List[AA] & List[BB] <: List[AA & BB]
时编译。这是真的吗?
如果是这样,则不是 List[AA] & List[BB] =:= List[AA & BB]
。请推荐
在我看来,List[AA & BB] =:= List[AA] & List[BB]
。考虑一下:
val xx: List[AA & BB] = ???
val yy: List[AA] & List[BB] = ???
val z1: List[AA] & List[BB] = xx
val z2: List[AA & BB] = yy
解决方法
您编写的 DD 要编译,List[AA] & List[BB]
必须是 List[AA & BB]
的子类型。我不明白你为什么这么认为,事实上你错了。方法返回类型是协变的,因此正好相反:List[AA & BB]
必须是 List[AA] & List[BB]
的子类型。而且确实是这样,所以代码没问题。
Matthias Berndt 已经回答说编译您的代码不需要 List[AA] & List[BB] <: List[AA & BB]
。然而,有一点是它实际上是正确的(List[AA] & List[BB] =:= List[AA & BB]
也是如此)。为什么?
- 考虑类型为
x
的值List[AA] & List[BB]
。 - 它必须同时是
List[AA]
和List[BB]
。 - 即,
AA
的列表和BB
的列表。 - 所以这个列表的任何元素
y
都必须是一个AA
因为x
是一个AA
的列表,一个BB
因为 {{1 }} 是x
的列表。 - 所以
BB
必须是y
。 - 由于
AA & BB
的每个元素都具有x
类型,因此AA & BB
具有x
类型。
此推理特定于 List[AA & BB]
,但它概括了 and not just to covariant types:
如果 List
是类型构造函数,那么可以使用以下三个规则简化 C
:
- 如果
C[A] & C[B]
是协变的,则C
- 如果
C[A] & C[B] ~> C[A & B]
是逆变的,则C
- 如果
C[A] & C[B] ~> C[A | B]
是非变体,则发出编译错误