我正在尝试编写一个泛型函数,它接受一个实现“++”的通用容器,但是我似乎无法正确使用语法。
def pagedRequest[A, C[_] <: Iterable](url: String, accumulator: C[A])(parser: (WSResponse) => C[A]): Future[Either[Result, C[A]]] = {
WS.url(url).get().flatMap { response =>
response.status match {
case OK =>
val data = accumulator ++ parser(response)
(response.json \ "paging" \ "next").asOpt[String] match {
case None => Future.successful(Right(data))
case Some(next) => pagedRequest(next, data)(parser)
}
case _ =>
Future.successful(Left(ProxiedResult(response)))
}
}
}
“数据”的类型保持可迭代[A],而不是C [A]。
答案 0 :(得分:0)
您的问题是++
运算符采用隐式CanBuildFrom
,其类型为Iterable
。
来自Scala源中的TraversableLike
和Iterable
:
def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = {
val b = bf(repr)
if (that.isInstanceOf[IndexedSeqLike[_, _]]) b.sizeHint(this, that.seq.size)
b ++= thisCollection
b ++= that.seq
b.result
}
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Iterable[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]]
因此,++
的结果为That
,其类型为Iterable
。我不认为你能做到你想做的事情而不会像那样丑陋......
答案 1 :(得分:0)
这样做的唯一方法似乎是明确的类型转换。
极简主义的例子:
1)没有类型转换,我们得到Iterable:
scala> def addup[A, C[A] <: Iterable[A]](a:C[A],b:C[A])=a ++ b
addup: [A, C[A] <: Iterable[A]](a: C[A], b: C[A])Iterable[A]
scala> addup(List(2,3,4,5),List(4,5,6,7))
res3: Iterable[Int] = List(2, 3, 4, 5, 4, 5, 6, 7)
2)使用类型转换,我们得到C [A]:
scala> def addupC[A, C[A] <: Iterable[A]](a:C[A],b:C[A])=(a ++ b).asInstanceOf[C[A]]
addupC: [A, C[A] <: Iterable[A]](a: C[A], b: C[A])C[A]
scala> addupC(List(2,3,4,5),List(4,5,6,7))
res4: List[Int] = List(2, 3, 4, 5, 4, 5, 6, 7)
(顺便说一下,当像Slick这样的库一起工作时会发生类似的问题。)
在你的情况下,你必须尝试这个::
def pagedRequest[A, C[A] <: Iterable[A]](url: String, accumulator: C[A])(parser: (WSResponse) => C[A]): Future[Either[Result, C[A]]] = {
WS.url(url).get().flatMap { response =>
response.status match {
case OK =>
val data = (accumulator ++ parser(response)).asInstanceOf[C[A]]
(response.json \ "paging" \ "next").asOpt[String] match {
case None => Future.successful(Right(data))
case Some(next) => pagedRequest(next, data)(parser)
}
case _ =>
Future.successful(Left(ProxiedResult(response)))
}
}
}