2

I have the next code:

import zio._

import scala.concurrent.Future

case class AppError(description: String) extends Throwable
// legacy-code imitation
def method(x: Int): Task[Boolean] = {
  Task.fromFuture { implicit ec => Future.successful(x == 0) }
}

def handler(input: Int): IO[AppError, Int] = {
  for {
    result <- method(input)
    _ <- IO.fail(AppError("app error")).when(result)
  } yield input
}

but this code does not compile, because compiler says result type is:

ZIO[Any, Throwable, Int]

How to convert from Task (where I call method) to IO?

4

1 回答 1

5

You'll need to decide what you want to do with Throwable errors which are not AppError.

If you decide you want to map them to an AppError you can do:

method(input).mapError {
  case ae: AppError => ae
  case other =>        AppError(other.getMessage)
}

If you want to refine those errors and only keep the ones that are AppError then you can use one of the refine* family of operators, which will keep errors that match the predicate and terminate the fiber otherwise.

method(input).refineToOrDie[AppError] // IO[AppError, Boolean]
// Or
method(input).refineOrDie { case ae: AppError => ae } // IO[AppError, Boolean]

Or if you want to assume that all errors from method are considered "Fiber terminating", then you can use .orDie to absorb the error and kill the fiber:

method(input).orDie // UIO[Boolean]

Or if you want to recover from the error and handle it a different way then you could use the catch* family

method(input).catchAll(_ => UIO.succeed(false)) // UIO[Boolean]

Finally if you wanted to have the result mapped into an Either you could use .either, which will lift the error out of the error channel and map it into Either[E, A]

method(input).either // UIO[Either[Throwable, Boolean]]

There is a great cheat sheet (though admittedly a bit out of date) here as well

于 2020-07-12T16:23:37.470 回答