![](/img/trans.png)
[英]Scala cats OptionT: Convert Future[Option[A]] to Future[Either[B]]
[英]Scala with cats IO/Either instead of Future/Exceptions
我正在采用IO
/ Either
來替換適用的Future
/ Exception
,但我需要以下代碼的幫助:
// some Java library
def dbLoad(id: Int): Int = {
throw new Exception("db exception")
}
// my scala code
sealed trait DbError extends Exception with Product
object DbError {
case object SomeError extends DbError
}
val load: Int => IO[Either[DbError, Int]] = { id =>
IO.fromFuture { IO { Future {
try { Right(dbLoad(id)) } catch { case NonFatal(e) => Left(SomeError) }
} } }
}
val loadAll: IO[Either[DbError, (Int, Int, Int)]] =
for {
i1 <- load(1)
i2 <- // call 'load' passing i1 as parameter, if i1 is 'right'
i3 <- // call 'load' passing i2 as parameter, if i2 is 'right'
} yield (i1, i2, i3) match {
case (Right(i1), Right(i2), Right(i3)) => Right((i1, i2, i3))
case _ => Left(SomeError)
}
我無法使其正常工作/編譯,請您幫我理解:
Left
如何避免執行對load
(在loadAll
)的后續調用?load
的調用成功,我如何在接下來的load
調用中使用它的right
值?謝謝大家
讓我首先列出我認為可以滿足您的需求的代碼,以及處理此類事情的典型方式,然后我將描述內容和原因,也許還有其他一些建議:
import cats.data.EitherT
import cats.effect.IO
import cats.implicits._
import com.example.StackOverflow.DbError.SomeError
import scala.concurrent.Future
import scala.util.control.NonFatal
import scala.concurrent.ExecutionContext.Implicits.global
object StackOverflow {
// some Java library
def dbLoad(id: Int): Int = {
throw new Exception("db exception")
}
// my scala code
sealed trait DbError extends Exception with Product
object DbError {
case object SomeError extends DbError
}
val load: Int => IO[Either[DbError, Int]] = { id =>
IO.fromFuture(
IO(
Future(dbLoad(id))
.map(Right(_))
.recover {
case NonFatal(_) => Left(SomeError)
}
)
)
}
val loadAll: EitherT[IO, DbError, (Int, Int, Int)] =
for {
i1 <- EitherT(load(1))
i2 <- EitherT(load(i1))
i3 <- EitherT(load(i2))
} yield (i1, i2, i3)
val x: IO[Either[DbError, (Int, Int, Int)]] = loadAll.value
}
首先,與IO[Future[_]]
try-catch 不同,Future 本身有許多組合器可以幫助您管理錯誤,假設您對返回的內容有一定的控制權。
當以這種“短路”方式應用 Scala 中的For-comprehensions時,如果第一次調用load(1)
失敗並出現左值,那么其余的推導式將不會執行。 使用EitherT
可以讓您管理您的Either
被“包裹”在效果類型中的事實。
這種方法存在一些問題,特別是在方差方面,您可以在此處閱讀有關它們的信息:
http://www.beyondthelines.net/programming/the-problem-with-eithert/
使用這種模式還有一些性能影響,您可能需要考慮
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.