尝试使用 Cats Effect Ref monad 来实现缓存功能。
为什么内部Ref没有按预期设置?
import cats.effect.kernel.Ref
import cats.effect.{IO, IOApp}
object SomeMain extends IOApp.Simple {
val cache: IO[Ref[IO, Option[String]]] = Ref.of[IO, Option[String]](None)
override def run: IO[Unit] = {
val checkValueBeforeSet = cache.flatMap(ref => ref.get.flatMap {
case Some(v) => IO(println(v))
case None => IO(println("as expected no value yet"))
})
val doSetAction = cache.flatMap(ref => ref.set(Some("abc"))).map(_ => println("set action done"))
val checkValueAfterSet = cache.flatMap(ref => ref.get.flatMap {
case Some(v) => IO(println(v))
case None => IO(println("unexpected still no value set!"))
})
for {
_ <- checkValueBeforeSet
_ <- doSetAction
_ <- checkValueAfterSet
} yield IO()
}
}
输出:
as expected no value yet
set action done
unexpected still no value set!
它不起作用,因为您每次都重新创建 Ref。
这个:
val cache: IO[Ref[IO, Option[String]]] = Ref.of[IO, Option[String]](None)
等同于:
val cache: () => AtomicReference[Option[String]] =
() => new AtomicReference(None)
您在某些辅助方法中使用了
cache
两次,这些方法正在创建本地 Ref
,然后让它被遗忘。
您必须保留
cache
返回的值并传递它(例如,使用依赖注入)才能完成这项工作:
import cats.effect.kernel.Ref
import cats.effect.{IO, IOApp}
object SomeMain extends IOApp.Simple {
val cache: IO[Ref[IO, Option[String]]] = Ref.of[IO, Option[String]](None)
override def run: IO[Unit] = cache.flatMap { ref =>
val checkValueBeforeSet = ref.get.flatMap {
case Some(v) => IO(println(v))
case None => IO(println("as expected no value yet"))
}
val doSetAction = ref.set(Some("abc"))).map(_ => println("set action done")
val checkValueAfterSet = ref.get.flatMap {
case Some(v) => IO(println(v))
case None => IO(println("unexpected still no value set!"))
}
for {
_ <- checkValueBeforeSet
_ <- doSetAction
_ <- checkValueAfterSet
} yield IO()
}
}
或者,您也可以使用
.memoize
,但如果您对自己在做什么没有很好的直觉,从长远来看,这是一种搬起石头砸自己脚的好方法。