问题描述
我试图熟悉Scala中类型较高的类型,因此我尝试实现这种简单的方法,该方法采用Option
的可遍历并将其平整,就像平整它一样。但是,由于函数返回类型Traversable[Any]
而不是T[S]
,所以编译器将引发错误。为什么会这样,如何使它正常工作?
def flatten[S,T[_] <: Traversable[_]](list: T[Option[S]]): T[S] = {
list.collect({ case Some(s) => s })
}
我认为可能是我错误地定义了T
的类型,但是我也尝试了T[_]: Traversable
和T[X] <: Traversable[X]
,但它们都不起作用。
当然可以,
def flatten[S](list: Traversable[Option[S]]): Traversable[S] = {
list.collect({ case Some(s) => s })
}
但是我不想丢失有关返回类型的输入类型信息(调用flatten(List[Option[T]])
应该返回List[T]
。
解决方法
这是因为collect
不返回T
,而仅返回Traversable
。特质Traversable
不知道继承它的任何类的类型。
此外,您的较高型类型是错误的,应该使用T[x] <: Traversable[x]
以避免存在类问题。您可以执行以下操作:
def flatten[S,T[x] <: Traversable[x]](list: T[Option[S]])(
implicit ev: collection.generic.CanBuildFrom[Traversable[Option[S]],S,T[S]]
): T[S] = list.collect { case Some(s) => s }
,否则Luis MiguelMejíaSuárez建议使用类型类可能会更好。我还建议尽可能使用Scala 2.13。
trait Flatten[F[_]] {
def flatten[S](list: F[Option[S]]): F[S]
}
object Flatten {
def flatten[S,F[_]](list: List[Option[S]])(implicit f: Flatten[F]) = f.flatten(list)
implicit val flattenList = new Flatten[List] {
def flatten[S](list: List[Option[S]]) = list.collect { case Some(s) => s }
}
}