假设我们想要创建一个类似于minBy
的函数,它返回集合中所有相等最小值的元素:
def multiMinBy[A, B: Ordering](xs: Traversable[A])(f: A => B) = {
val minVal = f(xs minBy f)
xs filter (f(_) == minVal)
}
scala> multiMinBy(List("zza","zzza","zzb","zzzb"))(_.last)
res33: Traversable[java.lang.String] = List(zza, zzza)
到目前为止,一切都很好,除了我们得到的是一个Traversable
而不是我们最初的List
。
于是我尝试将签名更改为
def multiMinBy[A, B: Ordering, C <: Traversable[A]](xs: C)(f: A => B)
我希望得到一个C
,而不是Traversable[A]
,但是我没有得到任何返回值:
scala> multiMinBy(List("zza","zzza","zzb","zzzb"))(_.last)
<console>:9: error: inferred type arguments [Nothing,Nothing,List[java.lang.String]]
do not conform to method multiMinBy's type parameter bounds [A,B,C <: Traversable[A]]
我认为这是因为在推断出 A
之前,C
出现在参数中了。因此,我颠倒了参数的顺序,并添加了一个强制转换:
def multiMinBy[A, B: Ordering, C <: Traversable[A]](f: A => B)(xs: C) = {
val minVal = f(xs minBy f)
(xs filter (f(_) == minVal)).asInstanceOf[C]
}
它是有效的,除了我们必须这样调用它:
multiMinBy((x: String) => x.last)(List("zza","zzza","zzb","zzzb"))
有没有一种方法可以保留原始语法,同时获取正确的集合类型返回?
GreaterLowerBound: TraversableLike[A, C]
吗?你是怎么知道需要这个才能使方法返回C的?我不太明白输入的具体类型保存在哪里。 - AdrianTraversable[A]
约束提供了仅依赖于项目类型A
的方法。TraversableLike[A, C]
则提供了不仅处理项目类型为A
的方法,而且还会返回类型C
的方法。因为它是C with TraversableLike[A,C]
,所以我可以在其上调用一个方法,并将返回相同的集合C
,而不是返回Traversable[A]
。filter
方法就是这种情况,如果没有此限制,它将不会返回C
。 - Daniel C. SobralTraversableLike
上的返回类型更具体。我本可以只使用TraversableLike
,但我猜测——我真的不记得了——如果我这样做,类型推断就无法工作。 - Daniel C. Sobral