根据评论中的一些建议,我研究了 CanBuildFrom,这就是我想出的:
import scala.collection.IterableLike
import scala.collection.generic.CanBuildFrom
/** Filters `xs` to have only every nth element.
*/
def everyNth[A, It <: Iterable[A]]
(xs: It with IterableLike[A, It], n: Int, offset: Int = 0)
(implicit bf: CanBuildFrom[It, A , It]): It = {
val retval = bf()
retval ++= xs.zipWithIndex collect { case (x, i) if (i - offset) % n == 0 => x }
retval.result
}
耶,它工作!
而且没有演员表。因此,它甚至适用于 Ranges。
但是,必须从一个空的 retval 开始,然后使用 "++=" 来填充它似乎有点不雅,所以如果有人有更优雅的解决方案,我会全神贯注。
这是我实现的另一个泛型函数,它比上面的要复杂一些,因为返回类型与参数类型不同。即输入是一个A
's序列,但输出是一个(A, A)
's序列:
def zipWithSelf[A, It[A] <: Iterable[A]]
(xs: It[A] with IterableLike[A, It[A]])
(implicit bf: CanBuildFrom[It[A], (A, A), It[(A, A)]]): It[(A, A)] = {
val retval = bf()
if (xs.nonEmpty) {
retval ++= xs zip xs.tail
retval.result
} else retval.result
}
这是另一个:
/** Calls `f(x)` for all x in `xs` and returns an Iterable containing the indexes for
* which `f(x)` is true.
*
* The type of the returned Iterable will match the type of `xs`.
*/
def findAll[A, It[A] <: Iterable[A]]
(xs: It[A] with IterableLike[A, It[A]])
(f: A => Boolean)
(implicit bf: CanBuildFrom[It[A], Int, It[Int]]): It[Int] = {
val retval = bf()
retval ++= xs.zipWithIndex filter { p => f(p._1) } map { _._2 }
retval.result
}
我仍然对“Like”类型和 没有任何深入的了解CanBuildFrom
,但我明白了要点。在大多数情况下,将泛型函数的强制转换版本编写为第一遍是很容易的,然后添加CanBuildFrom
和IterableLike
样板以使函数更通用和完全类型安全。