我正在阅读这篇(很棒的)帖子 A Generic Quicksort in Scala来自乔什·苏雷思。特别有趣的是关于延迟集合类型推断的部分。
现在我想知道这是否也适用于非集合。以下 2 个方法创建一个 Foo[T,O]
def sort1[T, O](from: T, to: T)(implicit ev: O <:< Ordering[T], ord: O):Foo[T,O] = {
...
}
def sort2[T, O <: Ordering[Int]](from: T, to: T)(implicit ord: O):Foo[T,O] = {
...
}
这两种方法中哪一种是首选,为什么?
sort2(2,5)
确实有效,使用 sort1(2,5)
编译器似乎发现了更多隐式,因为存在不明确的隐式解析错误。
最佳答案
使用generalized type constraints推迟类型推断都是为了绕过类型推断的限制。这些限制不一定是错误,它们可能是设计使然。
我可以想到它们有用的两种常见情况:
您想要获取另一个更高级类型中的类型,但您没有获取它的限制。
示例:
def sort[T, Coll <: SeqLike[T, Coll](a: Coll): Coll
编译器无法获取类型参数
T
因为它不以任何方式受到约束:它不会出现在<:
的左侧或>:
出现在类型形参列表中,并且不出现在实参的类型中。广义类型约束允许在这里约束(通过参数)类型
T
:def sort[T, Coll](a: Coll)(implicit ev: Coll <:< SeqLike[T, Coll]): Coll
注意:这只是实现此目的的一种方法。通常有一种方法可以在没有隐含证据的情况下获得
相同的东西非常接近的东西。这里应该是:def sort[T, Coll <: SeqLike[T, Coll]](a: Coll with SeqLike[T, Coll]): Coll
您无法控制类型参数,因为它来自封闭类。
例如,添加
flatten
方法List[A]
仅当A
时才有效本身就是一个集合。您无法更改类型参数A
仅适用于该方法,但您可以在本地添加带有implicit ev: A <:< Traversable[B]
的约束或类似的东西。注释 2:这不是集合库中所做的事情,它使用
implicit ev: (A) => Traversable[B]
,这样任何可以转换为集合的东西都可以工作(例如String
或Array
),但有时您不希望这样。
编辑以解决 sort1
与 sort2
问题:在不需要时添加广义类型约束可能会产生这种错误,因为类型变得约束不足。由于 O
没有限制在sort1
, ord: O
可以是任何东西。隐含证据只能用于查看O
作为Ordering[T]
在方法体内。
如果你真的想保留隐含的证据,你就必须在某个地方重新引入一些约束。关于类型参数,如sort2
,或ord
本身:
def sort3[T, O](from: T, to: T)
(implicit ev: O <:< Ordering[T], ord: O with Ordering[T]):Foo[T,O]
在本例中,sort2
似乎是最好的方法。
关于scala - 方法调用时的延迟类型推断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18182101/