2014-08-29 2 views
2

Я пытаюсь написать общую функцию, которая принимает общий контейнер, который реализует «++», однако я не могу получить синтаксис правильно.Общая функция с ограничениями типов

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))) 
    } 
    } 
} 

Тип «данных» сохраняется как Iterable [A], а не C [A].

ответ

0

Ваша проблема заключается в том, что оператор ++ принимает неявный CanBuildFrom, который напечатан на Iterable.

От TraversableLike и Iterable в источнике Scala:

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. Я не думаю, что вы можете делать то, что вы хотите сделать здесь, не отбрасывая как уродливые, как это может быть ...

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) с напечатанным, мы получаем С [А]:

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))) 
    } 
    } 
} 
Смежные вопросы