【发布时间】:2019-05-19 22:51:28
【问题描述】:
我有一个很重的副作用函数(想想数据库调用),我想将其用作惰性值,以便仅在第一次使用时调用它(如果从未使用过则根本不调用)。
如何使用 ZIO 做到这一点?
如果我的程序看起来像这样,那么函数只会被调用一次(但甚至根本不会使用结果):
import scalaz.zio.IO
import scalaz.zio.console._
object Main extends scalaz.zio.App {
def longRunningDbAction: IO[Nothing, Integer] = for {
_ <- putStrLn("Calling the database now")
} yield 42
def maybeUseTheValue(x: Integer): IO[Nothing, Unit] = for {
_ <- putStrLn(s"The database said ${x}")
} yield ()
def maybeNeedItAgain(x: Integer): IO[Nothing, Unit] = for {
_ <- putStrLn("Okay, we did not need it again here.")
} yield ()
override def run(args: List[String]): IO[Nothing, Main.ExitStatus] = for {
valueFromDb <- longRunningDbAction
_ <- maybeUseTheValue(valueFromDb)
_ <- maybeNeedItAgain(valueFromDb)
} yield ExitStatus.ExitNow(0)
}
我想我必须传递一个产生Int 的IO 而不是已经物化的Int,但是如果我传入只是调用数据库的原始IO,它将被重复调用:
object Main extends scalaz.zio.App {
def longRunningDbAction: IO[Nothing, Integer] = for {
_ <- putStrLn("Calling the database now")
} yield 42
def maybeUseTheValue(x: IO[Nothing, Integer]): IO[Nothing, Unit] = for {
gettingItNow <- x
_ <- putStrLn(s"The database said ${gettingItNow}")
} yield ()
def maybeNeedItAgain(x: IO[Nothing, Integer]): IO[Nothing, Unit] = for {
gettingItNow <- x
_ <- putStrLn(s"Okay, we need it again here: ${gettingItNow}")
} yield ()
override def run(args: List[String]): IO[Nothing, Main.ExitStatus] = for {
_ <- maybeUseTheValue(longRunningDbAction)
_ <- maybeNeedItAgain(longRunningDbAction)
} yield ExitStatus.ExitNow(0)
}
有没有办法将longRunningDbAction“包装”成让它变得懒惰的东西?
【问题讨论】:
-
什么决定是否需要再次调用数据库?这是在第一次调用中确定的吗?
-
@user3056052 它应该像 Scala 中的常规
lazy val dbResult = callDatabase()一样工作,即在第一次调用它时进行评估,然后再次返回相同的值(不做任何其他事情)。跨度>
标签: scala lazy-evaluation scalaz io-monad zio