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

为何Kotlin Arrow的bind仅在显式catch时抛出CancellationException?

为什么Kotlin Arrow的bind函数在try/catch中会抛出异常,而直接调用不会?

现象回顾

在Arrow 1.2.3的either作用域内,直接调用bind()处理Left值时不会抛出可见异常,either会正常返回对应的Left结果;但用原生try/catch包裹bind()调用时,会捕获到如下异常:

Got exception arrow.core.raise.NoTrace: kotlin.coroutines.cancellation.CancellationException should never get swallowed. Always re-throw it if captured.This swallows the exception of Arrow's Raise, and leads to unexpected behavior.When working with Arrow prefer Either.catch or arrow.core.raise.catch to automatically rethrow CancellationException.

改用Arrow内置的catch函数则能正常执行,不会触发该异常。

核心原因

  1. Arrow的bind基于内部异常实现控制流
    Arrow的either作用域和bind()函数依赖内部异常实现非局部返回:当bind()处理Left值时,会抛出一个Arrow内部的异常来中断当前代码流程,随后either作用域会捕获这个异常,并将其转换为Left类型返回。这个异常是Arrow控制流的一部分,并非业务异常,也不应该被用户的原生try/catch捕获。

  2. 原生try/catch破坏了Arrow的控制流
    当你用原生try/catch捕获了这个内部异常,either作用域就无法感知到bind()的Left分支,也就无法完成正常的流程转换。此时Arrow会抛出NoTrace异常来警告你:你吞掉了它的控制流异常,这会导致后续逻辑出现意外行为。

  3. CancellationException提示的误导性
    提示中提到的CancellationException和协程无关,这是因为Arrow的异常处理逻辑复用了协程环境中的安全规则——吞掉CancellationException会导致协程无法正常取消,而这里的场景是你吞掉了Arrow的控制流异常,Arrow用同样的警告逻辑来提醒你不要破坏它的内部流程,所以出现了这个看似不相关的提示。

为什么Arrow的catch函数可以正常工作?

Arrow内置的catch函数是专门为其控制流机制设计的,它会自动区分业务异常和Arrow内部控制流异常:

  • 对于业务代码抛出的异常,会交给你定义的处理逻辑处理
  • 对于bind()抛出的内部控制流异常,会重新抛给either作用域处理,保证原有的流程转换正常进行

总结

Arrow的bind()和either作用域的控制流依赖内部异常实现,原生try/catch会干扰这个机制,导致Arrow抛出警告异常。必须使用Arrow提供的catch函数来处理异常,才能和它的控制流正确协作。

内容的提问来源于stack exchange,提问作者John Schlachtenhaufen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 00:22:39