为什么可变和不可变集合中的类型推断表现如此不同?
Why does type inference in mutable and immutable sets behave so differently?
当运行以下代码时,我得到了一些奇怪的结果:
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]
}
为什么可变和不可变集合中的类型推断行为如此不同? z
部分最令人费解,为什么我们至少没有得到一个 TreeSet[Any]
?
问题可以简化成这样:
scala> TreeSet.empty[Int] ++ TreeSet.empty[BigInt]
res15: scala.collection.immutable.Set[Any] = Set()
您对 TreeSet.empty
的使用并没有透露它实际上是什么类型。事实上,它甚至不能按原样编译。我假设您在未显示的范围内有一些隐式 Ordering[A]
,其中 A != Int
.
关于问题:
Why didn't we at least get a TreeSet[Any]
简单的答案是,没有 Ordering[Any]
就不可能有 TreeSet[Any]
。如果我尝试将 TreeSet[Int]
与 TreeSet[BigInt]
组合起来,它们最常见的类型是 Any
。一个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()
但这并没有任何意义。
技术上的答案是,为了连接两个 TreeSet
,TreeSet[A]
和 TreeSet[B]
,我们需要一个隐含的 CanBuildFrom[TreeSet[A], B, TreeSet[B]]
.
有 一些 CanBuildFrom
由 SortedSetFactory
生成,但请注意它们如何需要隐式 Ordering[A]
。因为找不到 Ordering[Any]
,编译器会寻找更通用的东西,并找到 Set[Any]
。这是有道理的,因为如果我们将元素放入一个我们不知道如何排序的有序集合中,那么我们就不再有一个有序集合。剩下的就是一个普通的Set
.
当运行以下代码时,我得到了一些奇怪的结果:
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]
}
为什么可变和不可变集合中的类型推断行为如此不同? z
部分最令人费解,为什么我们至少没有得到一个 TreeSet[Any]
?
问题可以简化成这样:
scala> TreeSet.empty[Int] ++ TreeSet.empty[BigInt]
res15: scala.collection.immutable.Set[Any] = Set()
您对 TreeSet.empty
的使用并没有透露它实际上是什么类型。事实上,它甚至不能按原样编译。我假设您在未显示的范围内有一些隐式 Ordering[A]
,其中 A != Int
.
关于问题:
Why didn't we at least get a TreeSet[Any]
简单的答案是,没有 Ordering[Any]
就不可能有 TreeSet[Any]
。如果我尝试将 TreeSet[Int]
与 TreeSet[BigInt]
组合起来,它们最常见的类型是 Any
。一个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()
但这并没有任何意义。
技术上的答案是,为了连接两个 TreeSet
,TreeSet[A]
和 TreeSet[B]
,我们需要一个隐含的 CanBuildFrom[TreeSet[A], B, TreeSet[B]]
.
有 一些 CanBuildFrom
由 SortedSetFactory
生成,但请注意它们如何需要隐式 Ordering[A]
。因为找不到 Ordering[Any]
,编译器会寻找更通用的东西,并找到 Set[Any]
。这是有道理的,因为如果我们将元素放入一个我们不知道如何排序的有序集合中,那么我们就不再有一个有序集合。剩下的就是一个普通的Set
.