ZIO STM 没有变异

ZIO STM not mutating

这会打印出 5 不变的值:

import zio.stm._
import zio.Console
import zio.Runtime.{default => rt}

class TInt(n: TRef[Int]):
  def ++(): USTM[Unit] = n.update(_ + 1)
  override def toString: String = n.toString

object TInt:
  def make(n: Int): USTM[TInt] = TRef.make(n).map(TInt(_))

class Client:
  val stmN: USTM[TInt] = TInt.make(5)
  def increment: USTM[Unit] = stmN.flatMap(_.++())

val c = Client()
rt.unsafeRun(for
  _ <- c.increment.commit
  n <- c.stmN.commit
  _ <- Console.printLine(n)
yield ())

我怎样才能(使用最小 结构 更改)让它打印出增加的值?通过一些测试,我知道 TInt 是可靠的。我怀疑,这个问题必须与 Client.stmN 作为 USTM 而不是 反映 潜在的突变有关。

脱衣服 stmN: STM[TInt] 现在它只是 n: Tint 并且作为构造函数参数被跟踪。这需要将 Client 的构造有效地拉入 TRef.map:

import zio.stm._
import zio.Console
import zio.Runtime.{default => rt}

class TInt(n: TRef[Int]):
  def ++(): USTM[Unit] = n.update(_ + 1)
  override def toString: String = n.toString

object TInt:
  def make(n: Int): USTM[TInt] = TRef.make(n).map(TInt(_))

class Client(val n: TInt):
  def increment: USTM[Unit] = n.++()

object Client:
  def apply(): USTM[Client] = TInt.make(5).map(new Client(_))

rt.unsafeRun(for
  c <- Client().commit
  _ <- c.increment.commit
  _ <- Console.printLine(c.n)
yield ())

这样做的效果是 c 现在是返回值 w/in unsafeRun 的一部分。似乎 Client 需要用 USTM 包装起来,以便认真对待其可变性。一般来说,我发现最好不要在各种 classes w/in 组合树之间传播事务。虽然它确实有助于实现良好的 OO 设计,但很难获得所需的可变性。相反,请尝试将所有内容保持在相同 class 并仅使用 stm.T* 作为状态。