【问题标题】:Intersection types with Covariance具有协方差的交集类型
【发布时间】:2021-04-09 08:52:00
【问题描述】:

考虑以下内容:

trait AA {
    def children: List[AA]
}

trait BB {
    def children: List[BB]
}

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

当我们在CC 中覆盖children 时,被覆盖的方法是顶级方法的合并实体。因此返回类型 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] &amp; List[BB] &lt;: List[AA &amp; BB] 时才能编译。这是真的吗? 如果是这样,那么不是List[AA] &amp; List[BB] =:= List[AA &amp; BB]。请推荐


在我看来List[AA &amp; BB] =:= List[AA] &amp; 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

【问题讨论】:

    标签: scala generics dotty scala-3


    【解决方案1】:

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

    【讨论】:

    • 函数返回类型是协方差回答它。
    【解决方案2】:

    Matthias Berndt 已经回答您的代码编译不需要List[AA] &amp; List[BB] &lt;: List[AA &amp; BB]。但是,另外一点是它实际上是正确的(List[AA] &amp; List[BB] =:= List[AA &amp; BB] 也是如此)。为什么?

    1. 考虑一个x 类型的值List[AA] &amp; List[BB]
    2. 它必须同时是List[AA]List[BB]
    3. AAs 列表和BBs 列表。
    4. 因此,此列表的任何元素y 必须是AA,因为xAAs 的列表,而BB 是因为xBBs 的列表。
    5. 所以y 必须是AA &amp; BB
    6. 由于x 的每个元素都具有AA &amp; BB 类型,因此x 具有List[AA &amp; BB] 类型。

    这个推理特定于List,但它概括了and not just to covariant types

    如果C是一个类型构造函数,那么C[A] &amp; C[B]可以使用以下三个规则进行简化:

    • 如果C 是协变的,则C[A] &amp; C[B] ~&gt; C[A &amp; B]
    • 如果C 是逆变的,则C[A] &amp; C[B] ~&gt; C[A | B]
    • 如果C 是非变体,则发出编译错误

    【讨论】:

      猜你喜欢
      • 2018-08-28
      • 2019-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-12
      • 1970-01-01
      • 2015-10-07
      • 2023-03-04
      相关资源
      最近更新 更多