在这个参数化函数中,为什么我需要演员?我怎么能摆脱它呢?
/** Filters `xs` to have only every nth element.
*/
def everyNth[A <% Iterable[B], B](xs: A, n: Int, offset: Int = 0): A =
(xs.zipWithIndex collect { case (x, i) if (i - offset) % n == 0 => x }).asInstanceOf[A]
Run Code Online (Sandbox Code Playgroud)
如果我最后没有演员,我会收到以下错误消息:
type mismatch; found : Iterable[B] required: A
Run Code Online (Sandbox Code Playgroud)
这个函数(使用强制转换)适用于我尝试过的所有情况,我知道在REPL中输入类似下面的内容,Scala能够在不在参数化函数的上下文中正确推断结果类型:
scala> val a: Stream[Int] = (Stream.from(0).zipWithIndex collect { case (x, i) if (i + 3) % 5 == 0 => x })
a: Stream[Int] = Stream(2, ?)
scala> a take 10 force
res20: scala.collection.immutable.Stream[Int] = Stream(2, 7, 12, 17, 22, 27, 32, 37, 42, 47)
Run Code Online (Sandbox Code Playgroud)
请解释!
根据评论中的一些建议,我研究了 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
}
Run Code Online (Sandbox Code Playgroud)
是的,它有效!
而且没有演员阵容。因此,它甚至适用于范围。
然而,必须从一个空的 retval 开始,然后使用“++=”来填充它似乎有点不优雅,所以如果有人有更优雅的解决方案,我会洗耳恭听。
这是我实现的另一个通用函数,它比上面的函数有点棘手,因为返回类型与参数类型不同。即,输入是A' 的序列,但输出是(A, A)' 的序列:
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
}
Run Code Online (Sandbox Code Playgroud)
这是另一个:
/** 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
}
Run Code Online (Sandbox Code Playgroud)
我对“喜欢”类型和 仍然没有任何深入的了解CanBuildFrom,但我明白了要点。在大多数情况下,首先编写泛型函数的转换版本是很容易的,然后添加CanBuildFrom和IterableLike样板文件以使函数更通用且完全类型安全。