You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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特性共同导致的:

  1. Scala代码块的返回值规则:Scala中,代码块的返回值是块内最后一个表达式的结果。你的run方法里,第一个for推导式生成了一个IO[Unit],但这个值没有被使用、组合或返回,直接被丢弃;只有最后一个for推导式的IO[Unit]被作为run方法的返回值。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 12:47:10