TRef[A]
是可以参与 STM 事务的对不可变值的可变引用。其可变引用可以在事务内检索和设置,并被强制保证原子性,一致性并与其他事务的隔离。
TRef
在 STM 内存中发生改变时,使用了低级机制来创建事务。
创建一个 TRef
在事务内部创建TRef:
import zio._
import zio.stm._
val createTRef: STM[Nothing, TRef[Int]] = TRef.make(10)
或者在事务内创建一个TRef,然后立即提交该事务,这使您可以存储并传递一个值引用。
import zio._
import zio.stm._
val commitTRef: UIO[TRef[Int]] = TRef.makeCommit(10)
从 TRef 中取出值
从一次事务中取回结果值:
import zio._
import zio.stm._
val retrieveSingle: UIO[Int] = (for {
tRef <- TRef.make(10)
value <- tRef.get
} yield value).commit
或多次事务提交后取回值:
import zio._
import zio.stm._
val retrieveMultiple: UIO[Int] = for {
tRef <- TRef.makeCommit(10)
value <- tRef.get.commit
} yield value
给 TRef 设置一个值
设置该值将覆盖现的引用内容。
在单个交易中设置值:
import zio._
import zio.stm._
val setSingle: UIO[Int] = (for {
tRef <- TRef.make(10)
_ <- tRef.set(20)
nValue <- tRef.get
} yield nValue).commit
或(在)多次交易(中多次设置):
import zio._
import zio.stm._
val setMultiple: UIO[Int] = for {
tRef <- TRef.makeCommit(10)
nValue <- tRef.set(20).flatMap(_ => tRef.get).commit
} yield nValue
更新 TRef 中的值
update(A => A)
函数允许根据 TRef 中旧的值计算新的值。
在单次事务中更新值:
import zio._
import zio.stm._
val updateSingle: UIO[Int] = (for {
tRef <- TRef.make(10)
nValue <- tRef.updateAndGet(_ + 20)
} yield nValue).commit
或(在)多次事务(中多次更新):
import zio._
import zio.stm._
val updateMultiple: UIO[Int] = for {
tRef <- TRef.makeCommit(10)
nValue <- tRef.updateAndGet(_ + 20).commit
} yield nValue
修改 TRef 中的值
modify(A => (B, A)): B
函数和 update
相似,但是它允许返回一些(B 类型的)信息。
在单个事务中修改值:
import zio._
import zio.stm._
val modifySingle: UIO[(String, Int)] = (for {
tRef <- TRef.make(10)
mValue <- tRef.modify(v => ("Zee-Oh", v + 10))
nValue <- tRef.get
} yield (mValue, nValue)).commit
或(在)多次事务(中多次修改):
import zio._
import zio.stm._
val modifyMultiple: UIO[(String, Int)] = for {
tRef <- TRef.makeCommit(10)
tuple2 <- tRef.modify(v => ("Zee-Oh", v + 10)).zip(tRef.get).commit
} yield tuple2
使用例子
这是使用 TRef 在两个纤程之间传递值的例子:
import zio._
import zio.stm._
def transfer(tSender: TRef[Int],
tReceiver: TRef[Int],
amount: Int): UIO[Int] = {
STM.atomically {
for {
_ <- tSender.get.retryUntil(_ >= amount)
_ <- tSender.update(_ - amount)
nAmount <- tReceiver.updateAndGet(_ + amount)
} yield nAmount
}
}
val transferredMoney: UIO[String] = for {
tSender <- TRef.makeCommit(50)
tReceiver <- TRef.makeCommit(100)
_ <- transfer(tSender, tReceiver, 50).fork
_ <- tSender.get.retryUntil(_ == 0).commit
tuple2 <- tSender.get.zip(tReceiver.get).commit
(senderBalance, receiverBalance) = tuple2
} yield s"sender: $senderBalance & receiver: $receiverBalance"
在此示例中,我们为发送者和接收者创建并提交两个事务引用,以便能够提取它们的值。在接下来的步骤中,我们创建一个原子事务,仅在发送者帐户中有足够的可用余额时才更新两个帐户。然后,我们(fork)以异步运行它。在接下去的纤程中,我们暂停它的执行直到发件人余额发生变化(在这种情况下达到零为止)。 最后,我们提取两个帐户的新值并将其合并为一个结果。
ZTRef
和 Ref[A]
类似,TRef[A]
实际上是 ZTRef[+EA, +EB, -A, +B]
类型的别名, ZTRef[+EA, +EB, -A, +B]
是一个多态的事务性引用,支持 ZRef 所提供的所有运算。有关多态引用的更多讨论,请参见 ZRef
.