我正在寻找一种将多个 JsResult 组合成一个的方法。这是我第一次尝试不使用 Shapeless
def combineJsResult[A,B](res1: JsResult[A], res2: JsResult[B]): JsResult[(A, B)] = (res1, res2) match {
case (r1: JsError, r2: JsError) => r1 ++ r2
case (JsSuccess(r1, _), JsSuccess(d, _)) => JsSuccess(r1 -> d)
case (r1: JsError, _) => r1
case (_, r2: JsError) => r2
}
我想要的是一个采用 n JsResult 并将它们组合成单个 JsResult [(A,B,C,...)] 的函数。现在我知道了 scala 在抽象上的局限性。我使用 Shapeless 尝试了多个代码,但由于 JsResult 是类型构造函数和方差问题,它们都没有编译。这是我脑海中的算法:
编写一个以 Any 类型的 JsResult 的 HList 作为参数的函数。foldRight 在列表上使用 JsSuccess(HNil) 作为初始元素和上述函数的变体(将结果类型更改为 JsResult[HList])作为折叠函数。
这是我的最终代码(未编译)
import play.api.libs.json.{JsError, JsResult, JsSuccess}
import shapeless.{Generic, HList, HNil, Poly2}
object merger extends Poly2 {
def apply = at{ (res1: JsResult[_], res2: JsResult[_]) => {
(res1, res2) match {
case (r1: JsError, r2: JsError) => r1 ++ r2
case (JsSuccess(r1, _), JsSuccess(d, _)) => JsSuccess(r1 :: d :: HNil)
case (r1: JsError, _) => r1
case (_, r2: JsError) => r2
}
} }
}
def combineJsResults[P <: Product, L <: HList](p: P)(implicit gen: Generic.Aux[P, L]) = {
gen.to(p).foldRight[JsResult[HList]](JsSuccess(HNil))(merger)
}
combineJsResults(JsSuccess(1), JsSuccess("2"), JsSuccess(true))
非常感谢您帮助我了解如何解决此问题。
编辑:我取得了一些进展
import play.api.libs.json.{JsError, JsSuccess}
import shapeless._
object combine extends Poly2 {
def concatSuccess[L, R <: HList](l: JsSuccess[L], r: JsSuccess[R]): JsSuccess[L :: R] = JsSuccess(l.value :: r.value)
implicit def successSuccess[L, R <: HList] = at[JsSuccess[L], JsSuccess[R]](concatSuccess)
implicit def errorSuccess[R <: HList] = at[JsError, JsSuccess[R]]((l: JsError, r : JsSuccess[R]) => l)
implicit val errorError = at[JsError, JsError](_ ++ _)
implicit def successError[S] = at[JsSuccess[S], JsError]((l: JsSuccess[S], r: JsError) => r)
}
(JsSuccess(true) :: HNil).foldRight(JsSuccess(HNil))(combine)
(JsError("error") :: HNil).foldRight(JsSuccess(HNil))(combine)
val res1 = (JsSuccess(true) :: JsSuccess(1) :: HNil).foldRight(JsSuccess(HNil))(combine)
(JsError("error1") :: JsError("error2") :: HNil).foldRight(JsSuccess(HNil))(combine)
(JsSuccess(true) :: JsError("error2") :: HNil).foldRight(JsSuccess(HNil))(combine)
此代码编译,它成功地将 JsResult[_] 列表转换为 JsResult[HList] 现在我需要能够将该 HList 转换为元组以将其传递给案例类的元组方法。我查看了涉及使用 Generic 对象的示例,但它没有编译,因为 Generic[some case class].to 方法需要一个 Repr 参数而不是 HList。有没有人有任何想法?谢谢