ЗИО: Почему я получаю «Произошла непроверенная ошибка». - PullRequest
2 голосов
/ 20 октября 2019

У меня недоразумение с обработкой исключений в ZIO . Я следовал ZIO-документации .

В тестовом классе я выполняю следующий код:

  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 Ответ

3 голосов
/ 20 октября 2019

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

...