我有以下代码:
case class Foo[+CC[A] <: Iterable[A]](foo: CC[Int])
def customReduce[CC1[A] <: Iterable[A], CC2[A] <: Iterable[A]](foos: CC1[Foo[CC2]]): Foo[CC1] =
Foo(foos.flatMap(_.foo))
println(customReduce(Seq(Foo(Seq(1)))))
Foo是一个接受任何集合类型的类型。当我执行customReduce时,调用foos.flatMap
应该返回与foos相同的类型,即CC1[Foo[CC2]]
,但编译器将其解析为基Iterable
并抱怨:
type mismatch;
found : Iterable[Int]
required: CC1[Int]
为什么会发生这种情况,我该如何解决?
EDIT:在Iterable扩展IterableOps之后,CC类型似乎固定为Iterable。如何使上述代码正常工作?
在Scala 2.13中,您可以使用scala.collection.Factory
def customReduce[CC1[A] <: Iterable[A], CC2[A] <: Iterable[A]](foos: CC1[Foo[CC2]])(implicit
factory: Factory[Int, CC1[Int]]
): Foo[CC1] = Foo(foos.flatMap(_.foo).to(factory))
println(customReduce(Seq(Foo(Seq(1))))) // Foo(List(1))
这是我自己找到的解决方案:
由于flatMap
来自IterableOps,而Foo::foo
需要Iterable,因此我需要将CC1声明为IterableOps
和Iterable
:的复合类型
def customReduce[CC1[A] <: Iterable[A] with IterableOps[A, CC1, CC1[A]], CC2[A] <: Iterable[A]](foos: CC1[Foo[CC2]]): Foo[CC1] =
Foo(foos.flatMap(_.foo))
现在,由于返回原始CC 的IterableOps.flatMap
签名,flatMap正确解析为CC1