1

考虑以下内容:

trait AA {
    def children: List[AA]
}

trait BB {
    def children: List[BB]
}

class CC extends AA, BB {
    override def children: List[AA] & List[BB] = ???
}

当我们重写childreninCC时,被重写的方法是顶级方法的合并实体。因此返回类型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如果也 只能编译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
4

2 回答 2

5

您编写的 DD 编译List[AA] & List[BB]必须是List[AA & BB]. 我不明白你为什么这么想,事实上你错了。方法返回类型是协变的,因此反过来:List[AA & BB]必须是List[AA] & List[BB]. 而且确实是这样,所以代码没问题。

于 2021-01-03T10:51:06.530 回答
4

Matthias Berndt 已经回答List[AA] & List[BB] <: List[AA & BB]您的代码不需要编译。然而,一个单独的点是它实际上是正确的(也是如此List[AA] & List[BB] =:= List[AA & BB])。为什么?

  1. 考虑一个x类型的值List[AA] & List[BB]
  2. 它必须同时是 aList[AA]List[BB]
  3. 也就是说,一个AAs 列表和一个BBs 列表。
  4. 所以这个列表的任何元素y都必须是一个AA因为x是一个AAs的列表,一个BB因为x是一个BBs的列表。
  5. 所以y必须是一个AA & BB.
  6. 因为每个元素x都有类型AA & BB,所以x也有类型List[AA & BB]

这种推理是特定于 的List,但它概括了,而不仅仅是协变类型

IfC是类型构造函数,则C[A] & C[B]可以使用以下三个规则进行简化:

  • 如果C是协变的,C[A] & C[B] ~> C[A & B]
  • 如果C是逆变的,C[A] & C[B] ~> C[A | B]
  • 如果C是非变体,则发出编译错误
于 2021-01-03T13:27:21.127 回答