TRef[A] 是可以参与 STM 事务的对不可变值的可变引用。其可变引用可以在事务内检索和设置,并被强制保证原子性,一致性并与其他事务的隔离。 TRef 在 STM 内存中发生改变时,使用了低级机制来创建事务。 创建一个 TRef 在事务内部创建TRef: 或者在事务内创建一个TRef,然后立即提交该事务,这使您可以存储并传递一个值引用。 从 TRef 中取出值 从一次事务中取回结果值: 或多次事务提交后取回值: 给 TRef 设置一个值 设置该值将覆盖现的引用内容。 在单个交易中设置值: 或(在)多次交易(中多次设置): 更新 TRef 中的值 update(A => A) 函数允许根据 TRef 中旧的值计算新的值。 在单次事务中更新值: 或(在)多次事务(中多次更新): 修改 TRef 中的值 modify(A => (B, A)): B 函数和 update 相似,但是它允许返回一些(B 类型的)信息。 在单个事务中修改值: 或(在)多次事务(中多次修改): 使用例子 这是使用 TRef 在两个纤程之间传递值的例子: 在此示例中,我们为发送者和接收者创建并提交两个事务引用,以便能够提取它们的值。在接下来的步骤中,我们创建一个原子事务,仅在发送者帐户中有足够的可用余额时才更新两个帐户。然后,我们(fork)以异步运行它。在接下去的纤程中,我们暂停它的执行直到发件人余额发生变化(在这种情况下达到零为止)。 最后,我们提取两个帐户的新值并将其合并为一个结果。 ZTRef 和 Ref[A] 类似,TRef[A] 实际上是 ZTRef[+EA, +EB, -A, +B] 类型的别名, ZTRef[+EA, +EB, -A, +B] 是一个多态的事务性引用,支持 ZRef 所提供的所有运算。有关多态引用的更多讨论,请参见 ZRef.
TQueue[A] 是一个可以参与 STM 事务的可变队列。 创建一个 TQueue 创建一个具有指定容量的空的有界 TQueue: 创建一个空的无容量限制的 TQueue: 将元素加入一个 TQueue 将元素放入一个 TQueue: 如果队列未满,则指定的元素将被成功添加到队列中。否则,它将等待队列中的空插槽位。 另外,您可以使用一个元素列表来填充队列: 从 TQueue 中取回元素 您可以从队列中取回第一个元素,如下例: 如果队列为空,它将阻塞等待您所期待的元素。 可以通过使用 poll 方法来避免此阻塞行为,该方法将返回一个元素(如果存在)否则返回 None: 取回队列的前n个元素: 可以按以下方式获取队列的所有元素: TQueue 的大小 可以按以下方式获取队列中元素的个数:
TPromise 是一个可以设置一次,并且可以参与 STM 事务的可变参考。 创建一个 TPromise 创建一个 TPromise: 结束一个 TPromise 成功完成 TPromise: 得到一个失败的 TPromise: 另外,您也可以使用 done 组合器,并通过传递 Either[E, A] 来完成 Promise: 设置它的值后,之后任何尝试对其进行设置的操作都会返回 false。 从一个 TPromise 中得到值 如果 Promise 已经完成,则返回结果,否则返回 None: 或者,您可以(阻塞)等待 Promise 的完成并将值返回:
TPriorityQueue[A] 是一个可以参与 STM 事务的可变队列。一个 TPriorityQueue 中包含了类型为 A 的带有顺序定义的值。与 TQueue 不同,take 返回的是最高优先级(指定顺序中的第一个)值,而不是队列中的第一个值。当从队列中取出时,不保证共享相同优先级的元素的顺序。 创建一个 TPriorityQueue 您可以使用 empty 函数创建一个空的 TPriorityQueue: 请注意,TPriorityQueue 的创建使用了隐式 Ordering。默认情况下,take 将返回指定顺序中第一个的值。例如,在按时间排序的事件队列中,最早的事件将被首先取出。如果您想要不同的行为,可以使用自定义的 Ordering。 您还可以使用 fromIterable 或 make 构造函数创建一个使用指定元素初始化的TPriorityQueue。fromIterable 构造函数采用 Iterable,而 make 构造函数采用可变参数元素序列。 向 TPriorityQueue 添加元素 您可以使用 offer 或 offerAll 方法将元素添加入 TPriorityQueue。如果您要同时向队列添加多个元素,则 offerAll 方法会更加高效。 从 TPriorityQueue 中获取元素 使用 take 从 TPriorityQueue 中获取一个元素。take 在语义上会阻塞,直到队列中至少要取一个值为止。您还可以使用 takeAll 立即获取队列中当前的所有值,或使用 takeUpTo 立即获取队列中指定数量的元素。 您也可以使用 takeOption 方法从队列中获取第一个值(如果不存在也不会被挂起),或者使用 peek 方法观察队列中的第一个元素(如果存在)而不将其从队列中删除。 有时,您想要对队列的当前状态进行快照而不修改它。为此,toChunk 组合器或其变体 toList 或 toVector 非常有用。这些函数将返回一个不可变的集合,该集合由当前队列中的所有元素组成,而队列的状态保持不变。 TPriorityQueue 的大小 您可以使用 size 方法检查 TPriorityQueue 的大小:
TMap[A] 是一种可以参与 STM 事务的可变映射。 创建一个 TMap 创建一个空的 TMap: 或创建具有指定值的 TMap: 或者,您可以通过提供的元组集合来创建 TMap: 将键值对存入一个 TMap 可以通过以下方式将新的键值对添加到 map 映射: 在 map 中添加条目的另一种方法是使用 merge: 如果该键不存在于 map 中,则其行为类似于简单的 put 方法。否则,使用提供的函数将现有值与新值合并。 从 TMap 中删除元素 从 TMap 中删除键值对的最简单方法是使用采用 delete 删除某个键: 同样,它可以删除满足函数参数的每个键值对: 或者,您可以保留所有与函数参数匹配的键值对: 请注意,retainIf 和 removeIf 与 filter 和 filterNot 具有相同的目的。但是分别命名它们的原因是要强调其本质上存在的区别。也就是,retainIf 和removeIf 都是破坏性的,调用它们会修改原集合。(而 filter 和 filterNot 只是返回新集合而不修改原集合) 从 TMap 中读取 可以通过以下方式获取与键关联的值: 或者,如果 map 映射中不存在该键,则可以提供默认值: 转换 TMap 中的条目 函数 transform((K, V) => (K, V)) 可以用于为 map 映射中的每一个条目计算新的值: 请注意,它也可以用来压缩 TMap: TransformM 可以用于效果化地映射条目: 函数 transformValues(V => V) 可以为 map 中的每个值计算一个新值: 可以通过 transformValuesM 效果化地处理 map 中的这些值: 请注意,transform 和 transformValues 的用途与 map 和 mapValues 相同。 之所以分别命名它们的原因是要强调其本质上的区别。也就是说,transform 和 transformValues 都是破坏性的,调用它们可以修改原集合。 fold 使用指定的两个关联运算来遍历折叠 TMap 中的元素: foldM 可以效果化地折叠原属: 对 TMap 键值对执行side effect计算 foreach 用于对映射中的每个键值对执行 side-effect 计算: 检查 TMap 中的成员 检查键值对是否存在于 TMap 中: 将 TMap 转换为 List 可以通过以下方式转换成元组列表: 可以按如下方式获得键列表: 可以按以下方式获得值列表:
TArray 是可以参与 STM 事务的可变引用的数组。 创建一个 TArray 创建一个空的 TArray: 或创建具有指定值的 TArray: 或者,您可以通过指定的集合来创建 TArray: 从 TArray 读取值 可以通过以下方式获得数组的第 n 个元素: 访问不存在的索引会引发 ArrayIndexOutOfBoundsException 异常并中止事务。 更新 TArray 中的值 可以按照以下步骤更新数组的第n个元素: 可以通过 updateM 效果化地更新数组的第n个元素: 更新不存在的索引会引发 ArrayIndexOutOfBoundsException 并中止事务。 转换 TArray 的元素 transform(A => A) 函数可以为数组中的每一个元素计算新值: 可以通过 transformM 效果化地映射元素: fold 通过两个指定的运算遍历折叠 TArray 中的元素: 可以通过 foldM 效果化地进行遍历折叠: 对 TArray 元素执行 side-effect 运算 foreach 用于对数组中的每个元素执行 side-effect 运算:
ZLayer[A, E, B] 描述应用程序的一层:应用程序中的每个层都需要一些服务(作为输入)并产生出一些服务(作为输出)。Layers 可以被视基于给定他们的依赖关系(其他服务)而产生这些服务绑定所需要的清单。 层的构造可以使资源的使用效果化,并且使资源被安全地获取,使用完后安全地释放。 默认情况下,层(Layer)是共享的,这意味着如果同一图层使用两次,则该图层将仅分配一次。由于层具有出色的可组合性,因此它们是 ZIO 中创建依赖于其他服务的服务的惯用方式。 最简单的 ZLayer 应用 具有依赖项的 ZLayer 应用 复杂的 ZLayer 依赖案例
Chunk[A] 代表一大块类型为 A 的值。块的设计块通常由数组支持,但向下层元素公开纯函数式的,安全的接口,并且它们对使用数组代价高昂的操作(例如重复级联)采用懒模式。 新建一个块(chunk) 块连接(Concatenating): ++ 操作返回当前块与指定块的串联块。例如: 块搜集(collecting): collect 过滤、映射块中的元素并返回新的块。以下是如何使用 collect 函数从Chunk[A] 中挑选所有字符串的例子: 如何使用 collect 函数从 Chunk[A] 中挑选所有数字[A]: collectWhile (从左到右)收集元素,直到选择条件首次返回“ false”: 或者另外一个例子: 块删除(dropping): drop 函数从块中删除前 n 个元素。 dropWhile 依据条件函数删除所有返回 true 的元素: 块比较(Comparing): 块转换(Converting) toArray 将一个块转换成 Array。 toSeq 将一个块t转换成 Seq。
Stream[E, A] 表示一个可以产生 A 类型输出值,或可能以 E 类型为失败值的,效果化的流。 新建 Stream 或产生自 Iterable: 转换一个 Stream ZIO Stream 提供了许多标准的转换函数,例如:map,partition,grouped,groupByKey,groupedWithin等。以下是如何使用它们的示例。 map partition partition 根据函数参数将 stream 分成多个流元组。第一个流包含评估为 true的所有元素,第二个流包含评估为 false 的所有元素。较快的流可能比较慢的流领先,领先的程度受缓冲大小的限制。两个流都以 ZManaged 类型打包。在下面的示例中,左流仅包含偶数。 grouped 可以使用分组(grouped)函数将流的结果划分为指定的块大小。 groupByKey 可以使用 groupByKey 或 groupBy,按函数的执行结果对流进行分区。在下面的示例中,检查的结果被分组并计数。 groupedWithin groupedWithin 允许按时间或块大小对事件进行分组,以先满足者为准。在下面的示例中,每个块均最多包含 30 个元素,并且每 3 秒生成一次。 消费一个 Stream 使用 Sink Sink[E, A0, A, B] 表示接受的消费类型为 A,最终产生或者 E 型的错误, B 型的成功结果,以及剩余的类型为 A0。 例如,您可以使用 Sink.foldLeft 将 Stream 中的数据累加到单一个 ZIO 值: 在多个流上工作 您可以使用合并方法合并多个流: 或合并(zip)多个流: 然后您可以将流中的原属合并为单个 ZIO 值: 流压缩 解压 如果您读取到 Content-Encoding: deflate, Content-Encoding: gzip 或其它此类压缩数据流,则以下转换器可能会有所帮助: inflate 转换器可以根据 RFC 1951 标准对 deflated 格式的压缩输入流进行解压缩。 gunzip 转换器可以根据 RFC 1952 标准对 gzipped 格式的压缩输入流进行解压缩。 如果输入未经过正确的压缩,这两种解压缩方法都将以 CompressionException 作为失败类型。 压缩 deflate 转换器根据 RFC 1951 标准对流中的字节进行压缩。