【问题标题】:Why is GenSet declared to have invariant type parameter? [duplicate]为什么 GenSet 声明为具有不变类型参数? [复制]
【发布时间】:2013-06-27 20:53:51
【问题描述】:

我有一个类型 Foo,有子类型。

我有另一个类,其中包含一个 Foo:

class FooResult(val foo: Foo ...

我有一个 FooResult 集,我希望用 map() 将 Foos 从中拉出,然后计算该 Set (Foos) 和另一个 Foos 集之间的差异。下面的“结果”是一个 Set[FooResult] 并且 - 这是关键部分 - bundle 是一个 Set[_ <: foo>

val completedFoos = results.map(result => result.calc)
val unfinishedFoos = bundle.foos.diff(completedCalcs)

第二行不会编译。当 bundle 是 Set[Foo] 而不是 Set[_ <: foo>

type mismatch;
found   : Set[Foo]
required: scala.collection.GenSet[_$1]
Note: Foo >: _$1, but trait GenSet is invariant in type A.
You may wish to investigate a wildcard type such as `_ >: _$1`. (SLS 3.2.10)

我还没有找到任何简单的方法来解决这个问题。原谅我的无知,但是为什么像 GenSet 这样的“辅助”类型会被声明为不变的呢?

我是否遗漏了某些东西(很可能),或者这是否是 Scala 奇妙的集合框架的弱点(我认为不太可能)?

【问题讨论】:

    标签: scala scala-collections


    【解决方案1】:

    这是一个有意识的设计决定,使 Set.contains/apply 类型安全。你不应该有一个 s:Set[Int] 并且不小心做了像 s.contains("x") 这样的事情,这总是假的,所以可能不是你想要的。此外,Set[T] 实现了 Function[T,Boolean],这只有在 apply 方法不采用 Any 时才有可能。

    在 scala-user 邮件列表中关于这个话题的讨论无止境。参见例如thisthis

    下面是 Paul Phillips 在第二次讨论中的引述,很好地总结了基本原理:

    "是的,apply(别名为 contains)是 Set 的中心操作,而 contains 确实是 Seq 上的“只是一些方法”。

    没有人说你有时不需要协变集,但总的来说, 它是更有用的不变量。”

    请注意,您始终可以通过隐式转换为集合添加协方差。这意味着如果您有例如一个 Set[Int] 和一个采用 Set[Any] 的方法,它将起作用。但这也意味着你现在可能不小心调用了 Set[Int].contains("x"),编译器不会捕捉到错误(你总是会得到 false)。

    scala> implicit def setIsCovariant[T,U <: T](s:Set[U]):Set[T] = s.asInstanceOf[Set[T]]
    setIsCovariant: [T, U <: T](s: Set[U])Set[T]
    
    scala> val s : Set[Int] = Set(1,2,3,4)
    s: Set[Int] = Set(1, 2, 3, 4)
    
    scala> s.contains("x")
    res0: Boolean = false
    
    scala> val a: Set[Any] = s
    a: Set[Any] = Set(1, 2, 3, 4)
    

    【讨论】:

    • 好的 - 你或其他人能给我一些例子来说明我需要在上面做什么吗?是否需要建立新的收藏? (即使我想诉诸这种方法,我也不认为演员可以做到这一点。)谢谢!
    • 好吧,我只是让代码使用 [Foo] 而不是 [- <: foo>
    猜你喜欢
    • 2016-07-03
    • 2012-05-07
    • 2011-05-07
    • 2019-03-14
    • 2012-02-17
    • 2019-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多