错误通道与依赖通道
类型化错误与环境
错误通道与依赖通道 是 CoddyKit 上的免费 Scala for Backend Engineering & Functional Programming 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Scala for Backend Engineering & Functional Programming 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
两个强大的通道
除了成功值之外,ZIO[R, E, A] 还会跟踪类型化错误通道 E 和依赖通道 R。两者都会显示在类型中,因此失败情况和需求在编译时就是明确的。
类型化错误
将领域故障建模为一个密封层次结构,并将其放入 E 中。这样,编译器就会强制您恰好处理这些情况。
import zio._
sealed trait AppError
case object NotFound extends AppError
case object Forbidden extends AppError
val lookup: IO[AppError, String] = ZIO.fail(NotFound)使用 catchAll 恢复
catchAll 会通过提供一个新的效果来处理 E 中的所有错误。处理完成后,如果所有错误都已处理,错误通道可以变为 Nothing。
import zio._
val safe: UIO[String] =
ZIO.fail("boom").catchAll(e => ZIO.succeed(s"recovered: $e"))catchSome 与 orElse
catchSome 只恢复匹配的错误。orElse 会在发生任何失败时回退到另一个效果。
import zio._
val prog = ZIO.fail("x").orElse(ZIO.succeed("fallback"))Either 与 fold
either 会将 ZIO[R, E, A] 转换为 ZIO[R, Nothing, Either[E, A]]。fold 会将错误和成功统一处理为一个值。
import zio._
val label: UIO[String] =
ZIO.fail(404).fold(e => s"err $e", v => s"ok $v")缺陷与失败
ZIO 将失败(有类型、可预期,位于 E 中)与缺陷(意外抛出的异常)区分开来。ZIO.die 会引发缺陷;缺陷不属于 E 类型,而是表示程序错误。
环境 R
R 通道声明一个效果所需的服务。使用 ZIO.service 访问服务;在提供服务之前,该需求会一直出现在 R 中。
import zio._
trait Logger { def log(s: String): UIO[Unit] }
val prog: ZIO[Logger, Nothing, Unit] =
ZIO.serviceWithZIO[Logger](_.log("hello"))定义服务
服务由一个特征和一个用于构建它的 ZLayer 组成。层描述如何构造依赖,并且自身也可以依赖其他层。
import zio._
case class ConsoleLogger() extends Logger {
def log(s: String): UIO[Unit] = ZIO.succeed(println(s))
}
object ConsoleLogger {
val layer: ULayer[Logger] = ZLayer.succeed(ConsoleLogger())
}
trait Logger { def log(s: String): UIO[Unit] }提供依赖
provide(或 provideLayer)会满足 R 中的需求,将 ZIO[Logger, E, A] 转换为可以运行的 ZIO[Any, E, A]。
import zio._
val runnable: UIO[Unit] =
ZIO.serviceWithZIO[Logger](_.log("hi"))
.provide(ConsoleLogger.layer)
trait Logger { def log(s: String): UIO[Unit] }
object ConsoleLogger { val layer: ULayer[Logger] = ??? }组合层
层可以使用 ++(组合)进行水平组合,也可以使用 >>>(将一层的输出作为另一层的输入)进行垂直组合,从而构建完整的依赖图。
import zio._
// val appLayer = configLayer ++ (dbLayer >>> repoLayer)普通 Scala 基线实现
作为对比,这是一个手动处理错误的自包含 Scala 程序。ZIO 会在类型中编码相同的错误,并通过层注入依赖。
object Main {
def main(args: Array[String]): Unit = {
val result: Either[String, Int] = Left("NotFound")
val msg = result.fold(e => s"err $e", v => s"ok $v")
println(msg)
}
}快速检查
provide 方法会对 ZIO[Logger, E, A] 做什么?
回顾
您处理了两个额外的通道:
- 错误:类型化的
E、catchAll、orElse、fold,以及缺陷与失败的区别 - 依赖:
R、服务、ZLayer、provide和层组合
下一步:运行 ZIO 应用。
常见问题解答
「错误通道与依赖通道」课时是免费的吗?
是的 — 「错误通道与依赖通道」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Scala for Backend Engineering & Functional Programming 课程的其余内容,请升级到 CoddyKit PRO。 Scala for Backend Engineering & Functional Programming 课程共包含 4 节课。
「错误通道与依赖通道」这节课中我会学到什么?
类型化错误与环境 你通过在浏览器中直接运行的动手代码来练习 Scala for Backend Engineering & Functional Programming,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Scala for Backend Engineering & Functional Programming 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Scala for Backend Engineering & Functional Programming 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「错误通道与依赖通道」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Scala for Backend Engineering & Functional Programming 课中编写并运行代码吗?
能。每节 Scala for Backend Engineering & Functional Programming 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。