【问题标题】:Intersect Scala set with set of subtype将 Scala 集与子类型集相交
【发布时间】:2013-08-02 07:28:39
【问题描述】:

为什么这个函数不编译?

case class MyType(n: Int)
def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) =
  (s1 & s2)

我收到以下错误:

错误:类型不匹配;找到:设置 [_$1] 类型 _$1 _ <: MyType。 (SLS 3.2.10) (w & r)

有没有一种简单的方法可以在不使用 asInstanceOf 的情况下将第二个参数“提升”为 Set[MyType] 类型?

【问题讨论】:

    标签: scala generics


    【解决方案1】:

    这是因为Set 被定义为Set[A]。它是 in-variant 而不是协变的。

    &amp; 定义为

    def &(that: GenSet[A]): Set[A]
    

    它需要Set[A] 类型的参数。但是您提供的是Set[_ &lt;: MyType]

    Set[_ &lt;: Mytype]Set[MyType] 的协变体。但正如声明所说,参数应该是不变的,即Set[MyType],因此会出现错误。

    PS:您可以将协方差视为从窄到宽的类型转换。例如:如果Dog 扩展Animal 并且如果你这样做Animal a = new Dog(),你有一个狗(窄)转换为动物(宽)。上面它需要不变的类型。即,如果它需要Animal,您只能提供Animal。另一个例子是java.util.ArrayList,它是不变的。

    【讨论】:

    • 感谢您的解释。但是,现在我不知道为什么这个语句类型检查正确: Set(new Object()) & Set("string")
    • @tba 这是一个很好的观察。我在这里问过:stackoverflow.com/questions/18029746/…。谢谢
    【解决方案2】:

    Set 在其类型参数上不是协变的。

    所以一个简单的解决方案是转换为List(这是协变的):

    def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) =
        s1.toList.intersect(s2.toList).toSet
    

    【讨论】:

      【解决方案3】:

      Set 是不变的,但是有一个非常简单的解决方法:

      def intersection(s1: Set[MyType], s2: Set[_ <: MyType]) =
        s2 filter s1
      

      或者,如果想要为结果类型获得更好的类型推断:

      def intersection[X <: MyType](s1: Set[MyType], s2: Set[X]): Set[X] =
        s2 filter s1
      

      这里s1用作函数。函数的参数是逆变的,因此(MyType) =&gt; Boolean 类型的s1.apply 可以作为(_ &lt;: MyType) =&gt; Boolean 接受。

      性能与intersect 相同,因为this filter thatintersectSet 实现的方式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-03-25
        • 1970-01-01
        • 2021-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-30
        相关资源
        最近更新 更多