![](/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.