我知道 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
Run Code Online (Sandbox Code Playgroud)
从堆栈溢出。然而,它们仍然消耗 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))
Run Code Online (Sandbox Code Playgroud)
[编辑] 添加一个不同的例子,因为你真正需要的是:
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)
}
Run Code Online (Sandbox Code Playgroud)
但是请注意,我fork in run := true在你的build.sbt然后你还需要按照 sbt 文档中的run / connectInput := true解释添加