Cats Effect仅执行最后一个for推导式,其余被忽略原因咨询
Cats Effect 3中仅最后一个IO推导式执行的原因解析
问题重现
你编写的Cats Effect 3代码如下:
package com.scalaFPLove.FabioLabellaTalks import cats.effect.IOApp import cats.effect.{IO, Concurrent} import cats.effect.kernel.Deferred import cats.implicits._ import cats.kernel import cats.effect.kernel.Ref import cats.effect.unsafe.IORuntime.global object RefAndDeferredConcurrency extends IOApp.Simple { override def run: IO[Unit] = { for { _ <- IO.println("Hello1") _ <- IO.println("World1") } yield () for { _ <- IO.println("Hello2") _ <- IO.println("World2") } yield () } }
预期输出:
Hello1 World1 Hello2 World2
实际输出:
Hello2
World2
核心原因
这是Scala表达式求值规则结合Cats Effect IO特性共同导致的:
- Scala代码块的返回值规则:Scala中,代码块的返回值是块内最后一个表达式的结果。你的
run方法里,第一个for推导式生成了一个IO[Unit],但这个值没有被使用、组合或返回,直接被丢弃;只有最后一个for推导式的IO[Unit]被作为run方法的返回值。 - IO是描述性纯值:Cats Effect的
IO不是立即执行的命令,而是描述计算的纯值。只有当这个值被IOApp的Runtime执行时(也就是run方法返回的IO),对应的计算才会被触发。第一个IO因为没有被返回,所以永远不会被执行。
修复方案
要让两个IO都执行,需要把它们组合成一个单独的IO返回,常用方式有两种:
方式一:使用*>操作符组合
*>表示执行前一个IO,再执行后一个IO,忽略前一个的结果:
override def run: IO[Unit] = { (for { _ <- IO.println("Hello1") _ <- IO.println("World1") } yield ()) *> (for { _ <- IO.println("Hello2") _ <- IO.println("World2") } yield ()) }
方式二:合并为单个for推导式
直接把所有IO步骤放在同一个for推导式中:
override def run: IO[Unit] = { for { _ <- IO.println("Hello1") _ <- IO.println("World1") _ <- IO.println("Hello2") _ <- IO.println("World2") } yield () }
两种方式都能让两个IO序列执行,得到你预期的输出。
内容的提问来源于stack exchange,提问作者Somu
相关产品推荐
相关产品推荐

