运行 Effects

运行 Effects

ZIO 提供了多种不同的方式在您的应用程序中运行您的 effect。 App 如果您将整个程序构建一个 effect,那么运行 effect 的最自然的方法是扩展zio.App。 此类提供了 Scala 的 main 函数,因此可以从IDE调用它,或从命令行启动它。您所需要做的就是实现 run 方法,命令行参数被保存在 List 中作为参数传递给它: 如果您自定义了应用程序的环境,则必须(使用 ZIO#provide来)为您的 effect 的 run 函数提供环境,因为您(自定义的)的 App不知道如何将自定义的环境提供给 effect。 缺省的运行时 大多数应用程序不是全新的,必须与遗留代码,过程库和框架集成。 在这些情况下,更好解决方案是创建一个运行时,将其传递给需要运行 effect 的地方。 ZIO 包含一个名为 Runtime.default 的默认运行时。此运行时将所有 ZIO 提供的模块的实现(包括 Console,System,Clock,Random,Scheduler以及在 JVM 上的 Blocking)捆绑在一起,并且可以运行需要这些模块任意组合的 effect。 要使用这个运行时,只需使用: 一旦您获得了一个运行时,你就可以将它用于执行您的 effect: 除了unsafeRun方法之外,还有其他方法可以异步执行 effect 或将其转换为Future。 定制 Runtime 如果您使用自定义环境运行程序,那么创建专门针对该环境量身定制的运行时可能会很有用。 以下两个值用来创建自定义的 custom Runtime[R]: R Environment. 这是执行 effect 时将提供的环境。This is the environment that will be provided to effects when they are executed. Platform. 这是 ZIO 启动运行时系统所需的平台。 例如,以下代码使用 ZIO 提供的默认平台创建了一个可以将 Int 作为环境值提供给effect 的运行时: 错误报告 作为运行时的一部分,每一个 platform 都包含一个错误报告程序,ZIO 将调用该错误报告程序以报告每个未经处理的错误。提供您自己的错误报告程序是个好主意,比如可以将未处理的错误记录到文件中。 默认的未处理错误报告器仅将错误输出到标准错误输出。 Next Steps 如果您对运行效果感到满意,那就恭喜! 现在,您可以学习 ZIO 网站的其他部分,包括数据类型,用例以及与其他系统的互操作。. 有关所有核心 ZIO 类型和方法的详细文档,请参考 Scaladoc。

Effects测试

有许多方法可以测试 effect,包括使用 free monad,使用 tagless-final 和使用环境 effect。尽管所有这些方法都与 ZIO 兼容,但最简单,最符合习惯的是 环境 effect。 本节介绍 环境 effect,并向您展示如何使用它们来编写可测试的功能代码。 环境 ZIO 数据类型有一个类型参数 R,它用来描述 effect 所需的环境类型。 ZIO effects 可以使用 ZIO.environment 来访问环境,通过它直接得到 R 类型的环境值: 环境不必是整数等原始类型。它可能要复杂得多,比如可以是一个 trait 或 case class。 如果环境带有属性字段,则可以通过 ZIO.access 单个调用直接访问环境的给定部分: 甚至 effect 本身也可以存储在环境中!在这种情况下,要访问和执行 effect,可以使用 ZIO.accessM 方法。 如上例所示,从环境访问 effect 时,该效果称为 environment effect。 稍后,我们将看到环境 effect 是怎样提供一种简便的方法来测试 ZIO 应用程序的。 提供 Environments 必须先为 effect 提供(providing)环境,然后它们才能运行。 最简单的为一个 effect 提供所需环境的方法是使用 ZIO#provide 函数: 您为 effect 提供了所需的环境后,如果其返回的 effect 的环境类型为 Any (UIO[_]),这表明其要求已完全得到满足。 ZIO.accessM 和 ZIO#provide 的组合对于充分地利用环境 effect 来使得测试变得简单是必需的。 环境化的 Effects 环境 effect 背后的基本思想是面向接口编程,而非面向实现。对于函数式语言 Scala 而言,接口不包含任何具有副作用的方法,但是它们可能包含返回函数化了的effect 的方法。 与其在整个代码库中手动地实现依赖注入或者使用不连贯的隐式来传递接口,不如使用 ZIO Environment 来进行繁重的工作,从而使代码优雅,可推断且轻松自如。 在本节中,我们将通过开发可测试的数据库服务来探索如何使用环境 effect。 定义服务(Service) 我们以模块的形式定义数据库服务,该模块是仅包含单个字段的接口,该字段提供对服务的访问。 在这个例子中,Database 代表 模块,它包含了 Database.Service 服务。 这个 服务 只是一个普通的接口,定义在模块的伴随对象中,包含了该服务提供的功能函数。 辅助函数 为了简化访问数据库服务的环境 effect,我们将定义一些辅助函数来调用 ZIO.accessM。 虽然这些辅助函数不是必须的,因为我们可以直接通过 ZIO.accessM 来访问数据库模块,但是这些帮助程序易于编写并且使得调用端的代码看上去更简单。 调取服务 我们已经定义了一个模块和辅助函数,现在我们准备构建一个使用数据库服务的示例: 在此示例中,effect 仅能通过环境与数据库进行交互,在这种情况下,环境就成为一个提供对数据库服务的访问的模块。 要实际运行这个 effect,我们仅需要提供数据库模块的实现。 实现服务实体 现在我们将实现数据库模块的服务实体,它将切实负责与我们的生产厂数据库的交互: 在以上这段代码片段中,我们不打算提供这两个数据库方法的实现,因为这将需要超出本教程的范围。 运行数据库 Effect 现在我们有了一个数据库模块,和于数据库模块交互的辅助方法,可以一个数据库模块的具体实现。 我们现在使用  ZIO.provide 将数据库模块的实现提交给我们的应用程序: 自此,我们对产生出的 effect 没有了进一步的要求,所以现在可以将它提交给运行时去执行了。 实现服务的测试案例 为了测试代码于数据库的交互,我们不需要提供一个真实的数据库,因为这样的话我们的测试将会很慢很脆弱,并且即便应用的逻辑都是正确的也可能产生随机性的错误。 虽然我们可以使用模拟(mocking)库来创建测试模块,但是在本节中,我们将直接直接创建一个测试模块,以表明这里面没有任何魔术: 由于此模块仅在测试中使用,因此我们通过硬编码读取和更新 map 中的数据来模拟于数据库的交互。为了测试模块具有纤程安全性,可以使用 Ref 而不是 var 来定义 map。 测试数据库代码 现在要测试请求数据库的代码,我们只需要为它提供这个用于测试的数据库模块就可以了: 我们的应用程序代码可以像测试数据库模块一样使用在生产数据库模块上。 Next Steps 如果您对测试效果感到满意,那么下一步就是学习运行 effects。

基本并发处理

ZIO 的底层使用了 纤程 来支持多并发。 纤程非常强大,但是它们运行在底层,为了提高效率,ZIO 提供了基于纤程的上层操作。 如果可能,你应该总是选择使用上层操作,而不是直接和纤程打交道。为了完整起见,本节将介绍两种纤程以及在其上构建的一些上层操作。 纤程 Fibers ZIO 的并发是构建在 纤程 上的,它是一种由 ZIO 运行时系统实现的轻量级的“绿色线程”。 和操作系统线程不同,纤程几乎不占用内存,具有可伸缩的堆栈,不会浪费资源,并且如果纤程处于挂起和无法访问状态,则会自动被垃圾回收。 纤程是由 ZIO 运行时调度的,并且会相互协作产生,即使在单线程环境(例如JavaScript,甚至是只配置一个线程的 JVM)中运行时,也可以实现多任务处理。 ZIO 中的所有效果都是由某个纤程执行的。如果你没有创建过纤程,那么纤程将由正在当前的操作(如果该操作是并发的或并行的)或由 ZIO 运行时系统自动创建。 即使您仅编写“单线程”代码,没有并行或并发操作,也将至少有一个纤程,作为执行 effect 的“主”纤程。 Fiber 数据类型 每条 ZIO 纤程都负责执行着某个 effect,并且由 ZIO 的 Fiber 数据类型来代表该运行计算的“句柄”。Fiber 数据类型于 Scala 的 Future 数据类型很类似。 Fiber[E, A] 数据类型在 ZIO 中有两个参数: E Failure Type. 如果纤程运行失败,将返回这种类型的值。 A Success Type. 如果纤程运行成功,则返回这种类型的值。 纤程并没有代表环境类型的 R 参数,以为它们执行的 effects 已经处于运行状态了,并且也已经为他们提供了所需的环境。 效果分支 创建纤程的最基本方法是对一个已存在的 effect 执行 fork 操作。 从概念上讲,效果分叉后会在新的纤程上开始执行,并且返回对新创建的 Fiber 具柄。 下面的代码创建了一个纤程来执行 fib(100): Joining Fibers 从 Fiber 中返回一个 effect 的方法之一,是使用 Fiber#join。由方法 Fiber#join 返回的纤程可以是成功的,也可以是失败的: Awaiting Fibers 另一种纤程返回的方法是 Fiber#await,它返回一个包含返回值的 effect,该值提供了有关纤程如何完成的完整信息。 纤程的中断 可以中断不再需要结果的纤程从而立即终止纤程的执行,安全地释放所有资源并运行所有的终结器。 和 await 一样, Fiber#interrupt 返回一个纤程如何完成退出的说明。 根据设计,由 Fiber#interrupt 返回的 effect 将不可恢复直到纤程彻底完成后。如果不需要恢复它,则可以对中断本身使用 fork: 纤程的组合 ZIO 允许您使用  Fiber#zip 或 Fiber#zipWith 来组合纤程。 这些方法将两个纤程合并为一个单个的纤程,并产生两者的结果。如果任一个纤程发生失败,则合成的纤程也将失败。 另一个组合纤程的方法是使用 Fiber#orElse 函数。如果第一个纤程成功,那么组合将返回该成功值,否则组合将执行并返回第二个纤程的返回值。(无论是否成功) 并行 ZIO 提供了很多操作用于实现 effect 的并行。这些方法都以 Par 作为后缀以有助于您判断何时将采用并行。 例如, 普通的 ZIO#zip 方法将两个 effect 按序列运算并合并在一起。但是还有一个 ZIO#zipPar 方法,可以将两个 effect 并行执行并合并在一起。 下表总结了一些顺序操作及其对应的并行版本: Description Sequential Parallel Zips two effects into one ZIO#zip ZIO#zipPar Zips two effects into one ZIO#zipWith ZIO#zipWithPar Collects from many effects ZIO.collectAll ZIO.collectAllPar Effectfully loop over values ZIO.foreach ZIO.foreachPar Reduces many values ZIO.reduceAll ZIO.reduceAllPar Merges many values ZIO.mergeAll ZIO.mergeAllPar 对于所有并行操作,如果一个 effect 失败,则其他 effect 也将被中断,以最大程度地减少不必要的计算。 如果不希望这种快速失败的行为,则可以先使用 ZIO#either 或 ZIO#option […]

资源管理

本章节探讨使用 ZIO 来管理资源的通常的方法。 ZIO的资源管理功能包含了同步,异步,并发和其他 effect 类型,即使在应用程序出现故障,中断或缺陷的情况下,也能提供有力的保证。 Finalizing 通过  ZIO#ensuring  方法,ZIO 提供了类似 try / finally 的机制。 类似于 try / finally 一样, ensuring 函数可确保“终结器(finalizer)”将在一个 effect 开始执行然后终止(无论出于何种原因)后开始执行。 终结器是不允许失败的,这意味着它必须在内部处理所有的错误。 和 try / finally 一样,终结器可以嵌套,并且任何来自内部终结器的错误不会影响到它的外部终结器。嵌套终结器的执行顺序是反向,并且线性的(不是并行的)。 和 try / finally 不同的是,ensuring 可以工作于所有的 effect 类型,包括异步和并发 effect。 Bracket 通常 try / finally 被用于安全地获取和释放资源,例如一个新的 socket 的连接或一个文件的打开: ZIO 将这种通用模式封装在 ZIO#bracket 中,它允许您自动一个acquire effect 用于获取资源;一个 release effect 用于释放它;和一个 use effect 用于使用资源。 运行时系统将保证 release effect 的执行,哪怕存在错误或中断。 和 ensuring 一样,brackets 具有语意成分,所以如果一个 bracket 嵌套在另一个 bracket 里面,那么当外部 bracket 获取资源的时候,也就意味着这个外部 bracket’s 的 release 函数也将会被执行,无论它的内嵌 bracket 的释放失败与否。 Next Steps 如果您对资源处理感到满意,那么下一步就是学习基本并发处理。

错误处理

本章节探讨一些常用的检测和处理错误的方法。 Either 您可以使用  ZIO#either 来处理故障,方法是使用  ZIO[R, E, A]  并产生  ZIO[R, Nothing, Either[E, A]]。 您可以使用  ZIO.absolve 来将(Either 类型的)失败反转成 ZIO,这与上例相反,它将  ZIO[R, Nothing, Either[E, A]] 转换为 ZIO[R, E, A]: 捕获所有错误 如果您想捕获所有类型的错误并有效地尝试恢复,则可以使用 catchAll 方法: 在传递给 catchAll的回调中,您可以返回具有不同错误类型(或可能为Nothing)的 effect,并且它将被反映在 catchAll 返回的 effect 类型中。 捕获特定的错误 如果您只想捕获并恢复某些类型的异常,则可以使用 catchSome 方法: 于 catchAll 不同, catchSome 不能减少或消除所能包含的错误类型,但是它可以将错误类型扩展为更广泛的错误类别。 失败回退 您可以使用 orElse 组合器让它尝试一种 effect,如果它失败了,那么继续尝试执行另一个 effect。 Folding Scala 的 Option 和 Either 数据类型都具有 fold 方法,它可以让您同时处理成功和失败。ZIO  effect 也具有类似的几种方式可以让您处理失败和成功。 第一种方法是使用 fold,通过为每种情况提供一个非效果的函数,让您以 “非效果” 的方式同时处理成功和失败: 第二种方式是使用 foldM 函数,它允许您通过为每种情况提供效果化的(纯净的)处理程序,来处理失败和成功: 几乎所有错误处理方法都是根据 foldM 定义的,因为它既强大又快速。 在下面的例子中,foldM 被同时用于处理 readUrls 方法的成功和失败的: 重试 ZIO数据类型上有许多有用的方法可以重试失败的 effect。 ZIO#retry 是其中最基本的用法,它接收一个 Schedule 并返回一个会在前次执行失败后,基于指定的策略尝试重新执行的 effect: 另一个强大的函数是 ZIO#retryOrElse,它允许指定一个失败回退函数,如果效果指定的策略也无法取得成功,则执行回退函数: 最后,ZIO#retryOrElseEither 函数允许返回失败回退函数返回一个不同的类型: 有关如何新建一个 schedules,请参考 Schedule. Next Steps 如果您对基本的错误处理感到满意,那么下一步就是学习安全的 资源管理。

基本操作

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

创建 effect

本章节将探讨从直接量、常见的 Scala 类型,和同步、异步 side effect 中创建 ZIO effect 的一些常用方法。 必定成功的值 使用 ZIO.succeed 方法,你可以为一个特定值建立一个成功的 effect。: 也可以在 ZIO 的别名中使用这些方法: succeed 方法接收一个 by-name 参数以确保在构造该值时产生的任何 side-effect 都可以被 ZIO 的运行时适当地管理。但是 succeed 倾向于被用在没有任何 side-effect 的求值。如果你确定这个值会产生 side-effect,请考虑使用 ZIO.effectTotal 来声明: 这个成功效果的构造器 ZIO.effectTotal 只在必要的时候才会产生出值。 必定失败的值 使用 ZIO.fail 来为失败效果建模。 ZIO 数据类型不限定错误的类型,您可以使用适合您的应用程序的字符串,异常或自定义数据类型作为错误类型。 许多程序使用扩展自 Throwable 或 Exception 的类来为错误建模: 需要注意的是,不同于其它效果伴随对象,UIO 的伴随对象没有 UIO.fail,因为由 UIO 表达的 effect 不会失败。 取自 Scala 类型 很多来自 Scala 标准库的数据类型都可以被转换成 ZIO effect。 Option 可以通过  ZIO.fromOption 将 Option 转换成 ZIO effect: 它返回的错误效果类型是 Option[Nothing],它没有提供有关为何不存在该值的信息。你可以通过 ZIO#mapError 将 Option[Nothing] 映射到特定的错误类型: 你还可以轻松地组合不同的运算并保持“可选性”的结果 (与 OptionT 类似): Either 通过 ZIO.fromEither 可以将 Either 转换成 ZIO effect: 得到的 effect 中的错误类型将是任意的左值(Left)类型,而成功类型将是任意的右值(Right)类型。 Try 通过 ZIO.fromTry 可以将 Try 转换成 ZIO effect: 得到的 effect 中的错误类型总是 Throwable,因为 Try 只会以 Throwable 作为失败类型。 Function 通过 ZIO.fromFunction 可以将函数 A => B 转换成 ZIO effect 该 effect 的环境类型是 A (等于函数的输入类型),因为为了让该 effect 的到执行,我们必须提供该类型的输入值。 Future 通过 ZIO.fromFuture 可以将一个 Future 转换成 ZIO effect: 这个函数将一个  ExecutionContext 传递 fromFuture 函数,它将允许 ZIO 管理 Future 的运行 (当然,你也可以忽略该 ExecutionContext). 返回效果的错误类型总是 Throwable,因为 Future 只会以 Throwable 作为失败类型。 取自副作用(Side-Effects) ZIO可以将同步和异步 side-effect 都转换为ZIO effect(纯值)。 以下这些函数可用于包装过程代码,从而使您可以将ZIO的所有功能与遗留的 Scala 和 Java 代码以及第三方库无缝地结合使用。 同步 side-effect ZIO.effect 可以用于将有 side-effect 的同步代码转换成 ZIO: 结果的错误类型总是 Throwable,因为 side-effect 可能会引发任何类型的 Throwable 类型的异常。 如果给出的 side-effect 代码不会抛出任何异常,那么它可以用 ZIO.effectTotal 来转换。 当你使用 ZIO.effectTotal 的时候要特别小心 —— 如果你不能完全确定没有 side-effect,那么请使用 ZIO.effect 。 如果您希望细化效果的错误类型(将其他错误视为致命错误),那么可以使用 ZIO#refineToOrDie: 异步 side-effect ZIO.effectAsync 可以将一个基于回调 API 的异步 side-effect 转化成 ZIO effect: 与基于回调的API相比,异步 ZIO effect 更易于使用,并且它将受益于 ZIO 提供的功能,例如中断、资源安全和出色的错误处理。 阻塞的同步 Side-Effects 有一些 side-effect 代码使用阻塞 IO 或以某总方式使线程进入等待状态,如果你不小心加以管理,这些 side-effect 代码可能会耗尽应用程序主线程池中的线程,从而导致资源匮乏。 ZIO 提供了 zio.blocking 包,可以用于将阻塞 side-effects 安全地转换到 ZIO effects. […]

摘要

ZIO是一个基于纯函数式编程的的异步并发库。 有关如何在纯函数编程中处理“效果“,比如输入输出的背景知识,请参阅此章节:背景知识. ZIO 的核心是 ZIO,这是一种源自Haskell 的 IO monad的强大的效果类型。通过此数据类型,您可以通过简单的、类型安全的、可测试和可组合地的代码来解决复杂的问题。 ZIO ZIO[R, E, A] 数据类型有三个参数: R – Environment Type. 该效果通过一个类型 R 用以标示“环境”。如果此类型参数为Any,则表示对该效果没有要求,因为您可以使用任何值(例如单位值())。 E – Failure Type. 如果该类型有可能失败,以类型 E 来标示。有些应用中可以使用 Throwable. 如果该类型是 Nothing, 它标示该效果不可能失败,因为 Nothing 标示没有值可以提供。 A – Success Type. 该效果成功执行的返回类型标记为类型 A. 如果该类型参数返回 Unit, 这表示该效果没有产生有用的信息,如果返回的是 Nothing, 标示该效果将永远执行下去(直到失败为止)。 例如, 一个 ZIO[Any, IOException, Byte] 类型的效果表示它没有输入参数,可能导致 IOException 类型的失败,或成功返回 Byte 类型的返回值。 ZIO[R, E, A] 类型的值类似以下函数类型: 这个函数要求一个 R 类型的输入参数,将可能产生或者 E 类型的失败,或一个 A 类型的成功返回值。但是 ZIO 不完全等于是一个实际的函数,它是面向复杂的效果的模型,比如并发和并行效果。 类型别名 ZIO 数据类型是 ZIO 中唯一的效果数据类型.。但是,有一系列类型别名和伴随对象可以在不同情况下简化它的表达形式: UIO[A] — 这是 ZIO[Any, Nothing, A] 的别名,它表示一个对输入类型没有要求,并且不可能失败,并且能够成功返回一个 A 类型返回值的效果。 URIO[R, A] — 这是 ZIO[R, Nothing, A] 类型的别名,它表示输入要求为  R 类型,并且不可能失败,并能攻成功返回 A 类型的效果。 Task[A] — 这是 ZIO[Any, Throwable, A]的别名,表示一个对输入类型没有要起,可能导致 Throwable 类型的失败,或成功返回 A 类型的效果。 RIO[R, A] — 这是 ZIO[R, Throwable, A] 的别名,它表示一个输入类型为 R,可能导致 Throwable 类型的计算失败,或成功返回 A 类型的效果. IO[E, A] — 这是 ZIO[Any, E, A] 的别名,它表示对输入没有要求,并且可能导致 E 类型的失败,或成功返回 A 类型的效果。 这些别名都有一个伴随对象,并且这些对象具有可用于构造适当类型的值的方法。 如果您对函数的效果不熟悉,我们建议您从 Task 类型开始,它只有一个参数,并且与 Scala 标准库的 Future 最接近。 如果您正在使用 Cats Effect 库,则 RIO 类型可能会很有用,因为它允许您通过第三方库和应用程序对环境进行线程化。 无论您在应用程序中使用哪种类型的别名,UIO 都可用于描述不可能失败的效果,包括结果出自对错误的处理函数。 最后,如果您是经验丰富的函数式程序员,则建议直接使用 ZIO 数据类型,虽然您可能最终会在应用程序的不同部分中创建自己的类型别名。 下一步 如果您对ZIO数据类型及其类型别名系列感到满意,那么下一步就是学习如何 创建 effects.

Getting Started

在项目的 build.sbt 文件中添加以下配置来使用 zio 如果你想使用 ZIO streams,需要添加以下配置: Main 您的应用程序可以扩展自App,它提供一个完整的运行时(runtime)系统,并允许您使用 ZIO 编写整个应用程序。 run 方法应返回一个 ZIO 值,该值包括负责处理所有的错误, 在 ZIO 的术语环境中,它代表一个不会产生异常的 ZIO 值。 一种实现方法是在 ZIO 值上调用 fold,以获的非异常的 ZIO 值。这需要两个具柄函数:eh: E => B(错误处理具柄),和 ah: A => B(成功处理具柄)。 如果 myAppLogic 失败,则将使用 eh 从 e: E 获得 b: B;如果成功,则将使用 ah 从 a: A 获得 b: B。 以上为例,myAppLogic 产生一个非异常的 ZIO 值,其中 B 为 Int。 如果 myAppLogic 失败,将得到 1;否则如果成功,则将得到 0。 如果要使用依赖注入,将 ZIO 集成到现有应用程序中,或者不打算直接编写 main 函数,那么可以显式创建运行时(runtime)以执行 ZIO 程序: 理想情况下,您的应用程序应该只有一个运行时,因为每个运行时都有自己的资源(包括线程池和未处理的错误报告)。 控制台(Console) ZIO 提供了用于与控制台进行交互的模块。您可以使用以下代码片段将此模块中的功能导入. 如果需要将文本打印到控制台,则可以使用 putStr 和 putStrLn: 如果需要从控制台读取输入,则可以使用 getStrLn:

BACK TO TOP