scala - 如何在 ZIO 中实现不使用潜在大量堆空间的循环
问题描述
我知道 ZIO 维护自己的堆栈,即zio.internal.FiberContext#stack
保护递归函数,例如
def getNameFromUser(askForName: UIO[String]): UIO[String] =
for {
resp <- askForName
name <- if (resp.isEmpty) getNameFromUser(askForName) else ZIO.succeed(resp)
} yield name
从堆栈溢出。但是,它们仍然会占用 ZIO 解释器堆栈中的空间,这可能会导致OutOfMemoryError
非常深的递归。你将如何getNameFromUser
从上面重写函数,即使askForName
效果返回空字符串很长一段时间也不会破坏堆?
解决方案
您正在递归函数中使用循环。基本上,每次您调用时,getNameFromUser
您都在将对象分配给堆,堆永远无法释放这些对象,因为您在 t1 上创建的对象需要在 t2 中创建的对象来解析,但来自 t2 的对象需要在 t3 上的对象来解析无止境。
您应该使用 ZIO 组合器而不是循环,就像forever
您可以在Schedule上找到的任何其他组合器一样
import zio.Schedule
val getNameFromUser: RIO[Console, String] = for {
_ <- putStrLn("Waht is your name")
name <- zio.console.getStrLn
} yield name
val runUntilNotEmpty = Schedule.doWhile[String](_.isEmpty)
rt.unsafeRun(getNameFromUser.repeat(runUntilNotEmpty))
[编辑] 添加一个不同的示例因为你真正需要的是:
import zio._
import zio.console._
import scala.io.StdIn
object ConsoleEx extends App {
val getNameFromUser = for {
_ <- putStrLn("What is your name?")
name <- getStrLn
_ <- putStr(s"Hello, $name")
} yield ()
override def run(args: List[String]) =
getNameFromUser.fold(t => {println(t); 1}, _ => 0)
}
但是,请注意,我已经fork in run := true
在您的build.sbt
then 中,您还需要按照 sbt 文档中的run / connectInput := true
说明添加
推荐阅读
- node.js - 在特定房间使用 Socket.io 显示旧数据
- python - 谷歌日历api acl
- function - 如何访问在前一个函数中创建的第二个函数的标签数组?Win Forms App.NET
- android - 在 android studio 中构建 XML 按钮
- javascript - Javascript 代码在 WordPress 主题文件中不起作用
- javascript - Ag-grid:从 getRowNodeId 回调中检测到重复的节点 id 107,这可能会导致您的网格出现问题
- javascript - 条件渲染显示两个组件
- postgresql - 通过模糊匹配POSTGRESQL从数据库中获取地址
- angular - Visual Studio Code 智能感知未显示字符串的所有属性
- mysql - mySQL 在简单的 WHERE 查询上更新缓慢