Vamos a crear efectos funcionales de ZIO, y podemos hacerlo a partir de valores, cálculos y tipos de datos comunes de Scala.
Usando el método ZIO.succeed, se puede crear un efecto que, cuando se ejecute, tendrá éxito con el valor especificado:
val s1 = ZIO.succeed(42)
El método de succeed toma un parámetro, que garantiza que si le pasa al método algún código para ejecutar, este código se almacenará dentro del efecto ZIO para que ZIO pueda administrarlo y beneficiarse de características como reintentos, tiempos de espera y registro automático de errores.
Usando el método ZIO.fail, puede crear un efecto que, cuando se ejecuta, fallará con el valor especificado:
val f1 = ZIO.fail("Uh oh!")
Para el tipo de datos ZIO, no hay restricción en el tipo de error. Se puede usar cadenas, excepciones o tipos de datos personalizados.
Podemos usar excepciones :
val f2 = ZIO.fail(new Exception("Uh oh!"))
La biblioteca estándar de Scala contiene varios tipos de datos que se pueden convertir en efectos ZIO.
Un Option se puede convertir en un efecto ZIO usando ZIO.fromOption:
val zoption: IO[Option[Nothing], Int] = ZIO.fromOption(Some(2))
Option[Nothing], lo que significa que si dicho efecto falla, fallará con el valor Nothing (que tiene el tipo Opción[Nothing]).
Puede transformar una falla en algún otro valor de error usando orElseFail, uno de los muchos métodos que proporciona ZIO para la gestión de errores:
val zoption2: ZIO[Any, String, Int] = zoption.orElseFail("It wasn't there!")
ZIO tiene una variedad de otros operadores diseñados para facilitar el manejo de Option. En el siguiente ejemplo, los operadores Some y asSomeError se utilizan para facilitar la interfaz con los métodos que devuelven Option, similar al tipo OptionT en algunas bibliotecas de Scala.
val maybeId: ZIO[Any, Option[Nothing], String] = ZIO.fromOption(Some("abc123"))
def getUser(userId: String): ZIO[Any, Throwable, Option[User]] = ???
def getTeam(teamId: String): ZIO[Any, Throwable, Team] = ???
val result: ZIO[Any, Throwable, Option[(User, Team)]] = (for {
id <- maybeId
user <- getUser(id).some
team <- getTeam(user.teamId).asSomeError
} yield (user, team)).unsome
Un Some se puede convertirse en un efecto ZIO usando ZIO.fromEither:
val zeither: ZIO[Any, Nothing, String] = ZIO.fromEither(Right("Success!"))
El tipo de error del efecto resultante será el del caso Izquierdo (Left), mientras que el tipo de éxito será el del caso Derecho (Right).
Un valor Try se puede convertir en un efecto ZIO usando ZIO.fromTry:
import scala.util.Try
val ztry = ZIO.fromTry(Try(42 / 0))
El tipo de error del efecto resultante siempre será Throwable porque Try solo puede fallar con valores de tipo Throwable.
Un Scala Future se puede convertir en un efecto ZIO usando ZIO.fromFuture:
import scala.concurrent.Future
lazy val future = Future.successful("Hello!")
val zfuture: ZIO[Any, Throwable, String] = ZIO.fromFuture { implicit ec =>
future.map(_ => "Goodbye!")
}
La función pasada a fromFuture recibe un ExecutionContext, que permite a ZIO administrar dónde se ejecuta Future (por supuesto, puede ignorar este ExecutionContext).
El tipo de error del efecto resultante siempre será Throwable, porque los valores Future solo pueden fallar con valores de tipo Throwable.