如何处理Future结合尾递归时出现discarded non-Unit value报错问题
问题原因
你遇到的discarded non-Unit value报错和异步等待不生效的问题,核心来自两个错误:
- 你声明
recFoo返回值为Unit,但函数内部的for推导式最终会生成一个Future[Boolean]类型的值,你没有对这个值做任何处理也没有返回,编译器就会抛出「丢弃非Unit值」的报错 - 你当前的写法也无法实现「等待
futureFoo完成再调用下一次recFoo」的需求:因为递归调用recFoo(v)返回的是Unit,for推导式根本没法等待异步递归操作完成,相当于触发异步调用后就直接往下执行了
解决方案
把recFoo的返回值改成Future[Unit],通过for推导式的串行执行逻辑,等待上一步异步操作完成再执行递归即可:
import scala.concurrent.Future // 注意按需引入自己业务对应的ExecutionContext,不要直接用全局默认的也可以 import scala.concurrent.ExecutionContext.Implicits.global def futureFoo() = { Future.successful(true) } // 返回值改成Future[Unit]而非Unit def recFoo(x: List[Int]): Future[Unit] = { if (x.isEmpty) { // 空列表直接返回已完成的Unit类型Future Future.successful(()) } else { for { b <- futureFoo() v = getNewListOfValues(x.last) // 这里用<-而非=,等待递归返回的Future完成再往下走 _ <- recFoo(v) } yield () // 最终返回Unit,匹配函数声明的返回值类型 } }
补充说明
- 如果你调用
recFoo的地方不需要等待整个递归完成,也不需要处理返回结果,建议调用后补充异常捕获逻辑,比如recFoo(xxx).failed.foreach(e => 打印/上报错误),避免异步异常被静默吞掉 - 不需要强行用while循环实现该逻辑,Scala的while是同步语法,无法感知异步操作的完成状态,递归配合Future返回是更符合异步编程规范的实现方式
内容的提问来源于stack exchange,提问作者shinzou
相关产品推荐
相关产品推荐

