Mapping
您可以通过调用 ZIO#map
方法让 effect 在成功通道上进行映射。这使您可以转换effect 的成功值。
import zio._
val succeeded: UIO[Int] = IO.succeed(21).map(_ * 2)
您可以通过调用 ZIO#mapError
方法让效果在错误通道上进行映射。这使您可以转换 effect 的失败值。
val failed: IO[Exception, Unit] =
IO.fail("No no!").mapError(msg => new Exception(msg))
注意,在 effect 的成功或错误通道上进行映射不会更改效果的成功或失败,就如同 Either
,在任何一个通道上映射都不会改变它是 Left
还是 Right
。
链式调用
您可以使用 flatMap
方法串联执行两个 effects,这要求您提供一个回调函数,该回调接收第一个 effect 的输出作为它的输入,最终的返回取决于此第二个 effect 的结果:
val sequenced =
getStrLn.flatMap(input => putStrLn(s"You entered: $input"))
如果第一个 effect 失败了,那么传递给 flatMap
的回调将不会被执行,并且 flatMap
返回的合成效果也将失败。
在 任何 的效果链中,第一个失败将会直接导致整个调用链立即终止,就像抛出异常会提早从一系调用中退出一样。
For Comprehensions
因为 ZIO
数据类型同时支持 flatMap
和 map
调用,所以你可以使用 Scala 的 for comprehensions 来构建 effect 的执行序列:
val program =
for {
_ <- putStrLn("Hello! What is your name?")
name <- getStrLn
_ <- putStrLn(s"Hello, ${name}, welcome to ZIO!")
} yield ()
For comprehensions 提供了用于组合效果链的更具过程性的语法。
Zipping
您可以使用 ZIO#zip
方法将讲个 effect 合并成一个单个的 effect,产生的 effect 是一个包含了两个 effect 的成功值的元组:
val zipped: UIO[(String, Int)] =
ZIO.succeed("4").zip(ZIO.succeed(2))
要注意 zip
运算的顺序:左边效果的运算先于右边。
在任何一个 zip
运算中,如果左边或右边中的任意一边失败,那么整个effect组合都将失败,因为生成元组需要两个值。
有时候一个成功的 effect 的返回值是无用的(比如 Unit
),那么可以使用 ZIO#zipLeft
或 ZIO#zipRight
函数来方便地舍弃,这个些函数先执行 zip
,然后执行映射(map)来丢弃一边:
val zipRight1 =
putStrLn("What is your name?").zipRight(getStrLn)
zipRight
和 zipLeft
函数分别可以使用符号别名 *>
和 <*
来代替。有些开发者认为以下代码的可读性更高:
val zipRight2 =
putStrLn("What is your name?") *>
getStrLn
Next Step
如果您对ZIO effect 的基本操作感到满意,那么下一步就是学习错误处理.