2

我正在阅读 Josh Suereth 的(很棒的)帖子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)因为存在模棱两可的隐式解析错误,编译器似乎发现了更多隐含。

4

2 回答 2

1

使用广义类型约束推迟类型推断就是要绕过类型推断的限制。这些限制不一定是错误,它们可以是设计使然。

我可以想到两种有用的常见情况:

  • 您想在另一个更高种类的类型中获取该类型,但您没有获得它的约束。

    例子:

    def sort[T, Coll <: SeqLike[T, Coll](a: Coll): Coll
    

    编译器无法获取类型参数T,因为它不是任何形式的约束:它不会出现在 a 的左侧<:>:类型参数列表中,也不会出现在实参的类型中。

    广义类型约束允许在这里(通过参数)约束类型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仅针对该一种方法更改类型参数,但您可以在本地添加具有 animplicit ev: A <:< Traversable[B]或类似内容的约束。

    注意 2:这不是在使用 的集合库中所做的implicit ev: (A) => Traversable[B],因此任何可以转换为集合的东西都可以工作(例如StringArray),但有时您不希望这样做。

编辑以解决sort1vssort2问题:在不需要时添加通用类型约束可能会产生这种错误,因为类型变得约束不足。O由于in没有约束sort1ord: O可以是任何东西。隐含的证据只能用于将 anO视为Ordering[T]方法体内的 an。

如果您真的想保留隐含的证据,则必须在某处重新引入一些约束。在类型参数上sort2,如 in 或ord本身:

def sort3[T, O](from: T, to: T)
  (implicit ev: O <:< Ordering[T], ord: O with Ordering[T]):Foo[T,O]

在这种情况下,sort2似乎是最好的方法。

于 2013-08-12T11:51:22.160 回答
1

事实上,这似乎不直观。

原因是 sort1 对 O 没有定义任何约束,所以 'ord: O' 是模棱两可的。(对第一个隐式参数的约束只定义了对 'ev' 类型的约束)。

希望能帮助到你 :)

于 2013-08-12T08:45:24.120 回答