为什么可变和不可变集合中的类型推断表现得如此不同?

qed*_*qed -1 scala type-inference

运行以下代码时,我得到了一些奇怪的结果:

object Example {

  implicit object StringOrdering extends Ordering[String] {
    def compare(o1: String, o2: String) = {
      o1.length - o2.length
    }
  }
  object StringOrdering1 extends Ordering[String] {
    def compare(o1: String, o2: String) = {
      o2.length - o1.length
    }
  }


  import collection.mutable
  import collection.immutable.TreeSet

  val x = TreeSet(1, 5, 8, 12)
  val y = mutable.Set.empty ++= x // mutable.Set[Int]
  val y1 = mutable.Set.empty[Int] ++= x // mutable.Set[Int]
  val z = TreeSet.empty ++ y // Set[Any]
  val z1 = TreeSet.empty[Int] ++ y // TreeSet[Int]
}
Run Code Online (Sandbox Code Playgroud)

为什么可变和不可变集合中的类型推断表现得如此不同?这z部分是最令人费解的,为什么我们至少得不到TreeSet[Any]

Mic*_*jac 5

问题可以简化为这样的事情:

scala> TreeSet.empty[Int] ++ TreeSet.empty[BigInt]
res15: scala.collection.immutable.Set[Any] = Set()
Run Code Online (Sandbox Code Playgroud)

你的使用TreeSet.empty并没有透露它实际上是什么类型.实际上,它甚至没有按原样编译.我假设你有一些隐含Ordering[A]的范围,你没有显示,我在哪里运作A != Int.

关于这个问题:

为什么我们至少得不到TreeSet [Any]

简单的答案是,你不能有一个TreeSet[Any]没有Ordering[Any].如果我尝试将a TreeSet[Int]与a 组合TreeSet[BigInt],则最常见的类型是Any.A TreeSet是一种类型SortedSet,但我们如何对一组进行排序Any?默认情况下,我们不能,因为排序一组真的没有意义Any.

Ordering[Any]如果我真的想要,我可以设想一个,我最终得到一个TreeSet[Any]:

implicit val ordAny = new Ordering[Any] {
    def compare(x: Any, y: Any): Int = Ordering.Int.compare(x.hashCode, y.hashCode)
}

scala> TreeSet.empty[Int] ++ TreeSet.empty[BigInt]
res8: scala.collection.immutable.TreeSet[Any] = TreeSet()
Run Code Online (Sandbox Code Playgroud)

但这没有任何意义.

该技术的答案是,为了连接两个TreeSetS,TreeSet[A]并且TreeSet[B],我们需要一个隐含的CanBuildFrom[TreeSet[A], B, TreeSet[B]].

一些 CanBuildFrom是由生成的SortedSetFactory,但请注意它们如何需要隐式Ordering[A].因为Ordering[Any]找不到,所以编译器会寻找更通用的东西,然后找到Set[Any].这是有道理的,因为如果我们将元素放入一个我们不知道如何排序的有序集中,那么我们就不再有一个有序集.剩下的只是一个平原Set.