我正在阅读Josh Suereth的(好)帖A Generic Quicksort in Scala。特别有趣的是关于延迟收集的类型推断的部分。
现在我想知道这是否也适用于非收藏品。以下两种方法创建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)
编译器似乎发现更多隐含,因为存在模糊的隐式解析错误。
答案 0 :(得分:1)
原因是sort1没有对O定义约束,因此'ord:O'是不明确的。 (第一个隐式参数的约束只定义了'ev'类型的约束。)
希望有所帮助:)
答案 1 :(得分:1)
使用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]
的集合库中完成的操作,因此可以转换为集合的任何内容都可以工作(如{{1} }或String
),但有时你不希望这样。
修改以解决Array
vs 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]
似乎是最好的方法。