ZIO:为什么我得到“产生了未经检查的错误”。

时间:2019-10-20 10:52:59

标签: scala zio

我对 ZIO 中的异常处理有误解。我遵循了ZIO-Documentation

在测试类中,我运行以下代码:

  new DefaultRuntime {}.unsafeRun(
    (for {
      peopleRef <- Ref.make(Vector(People()))
      _ <- people(2).provide(Test(peopleRef)) // this throws the exception
    } yield ())
      .fold(
        err =>
          err shouldBe ServiceException("No People with id 2"), 
        _ => fail("line above should fail")
      )
  )

我认为使用fold函数可以处理此异常,但是它甚至没有到达那里。我在控制台上收到此异常:

Fiber failed.
An unchecked error was produced.
pme123.zio.examples.swapi.package$ServiceException
    at pme123.zio.examples.swapi.Swapi$Test$$anon$4.$anonfun$people$6(Swapi.scala:57)
    at zio.ZIO$MapFn.apply(ZIO.scala:2590)
    at zio.ZIO$MapFn.apply(ZIO.scala:2588)
    at zio.internal.FiberContext.evaluateNow(FiberContext.scala:709)
    at zio.Runtime.unsafeRunAsync(Runtime.scala:93)
    ....

我想念什么?

这是一个最小的示例:

object MyApp
  extends App {

  def run(args: List[String]): ZIO[Environment, Nothing, Int] =
    program
      .fold({ error => 1 // this is not reached
      }, _ => 0)

  private lazy val program = for {
    peopleRef <- Ref.make(Vector(22))
    _ <- Test(peopleRef).people(12)
  } yield ()

  case class Test(ref: Ref[Vector[Int]]) {

    def people(id: Int): Task[Int] =
      for {
        ints <- ref.get
      } yield ints.find(_ == id) match {
        case None => throw new IllegalArgumentException(s"No People with id $id") // this is thrown
        case Some(p) =>  p
      }
  }
}

下面是整个代码:SwapiTest.scala

1 个答案:

答案 0 :(得分:3)

ZIO不会捕获异常,除非将其包装在ZIO中。您可以使用ZIO.effect来包装整个遗留的不安全代码引发异常的块,也可以仅使用IO.fail来处理特定的异常。

我将您的代码重构为更类似于ZIO并产生失败的Task而不是引发异常:

case class Test(ref: Ref[Vector[Int]]) {

  def people(id: Int):Task[Int]=
    for {
      ints <- ref.get
      int  <- ZIO.effectTotal(ints.find(_ == id))
      res  <- int match {
        case None => IO.fail(new IllegalArgumentException(s"No People with id $id"))
        case Some(p) =>  ZIO.effectTotal(p)
      }
    }  yield res

}

要抓住IllegalArgumentException,您需要进行以下折叠:

...

.fold(
    err => err shouldBe IllegalArgumentException("No People with id 2"), 
    _   => fail("line above should fail")
 )

ServiceException不应出现在这里,因为没有东西抛出。