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

如何结合Context Receivers与Arrow 1.2.0的parZipOrAccumulate并行调用带Raise上下文的函数并累积错误?

如何结合Context Receivers与Arrow 1.2.0的parZipOrAccumulate并行调用带Raise上下文的函数并累积错误?

嘿,我完全懂你遇到的这个编译问题——那些带context(Raise<ApplicationError>)的getUser和getDepartment函数,没法直接塞进parZipOrAccumulate的lambda里,因为当前函数的上下文是Raise<Nel<ApplicationError>>,类型根本不匹配嘛!别着急,咱们一步步搞定它。

问题根源

getUser和getDepartment期望的是一个能抛出单个ApplicationError的上下文,但你的execute函数运行在一个能抛出Nel<ApplicationError>(非空错误列表)的上下文中。两者的上下文要求不兼容,所以编译器才会报错说找不到所需的上下文接收器。

解决方案:上下文转换+错误包装

我们需要做的就是把单个错误的上下文,适配成能累积成错误列表的上下文。Arrow的Raise提供了withRaise函数,正好能帮我们完成这个转换——它会把当前的Raise<Nel<ApplicationError>>上下文,临时转换成getUser/getDepartment需要的Raise<ApplicationError>上下文,同时把抛出的单个错误自动包装成Nel(非空列表),传递回上层上下文供parZipOrAccumulate累积。

修改后的代码如下:

context(Raise<Nel<ApplicationError>>)
override suspend fun execute(param: AddUserToDepartmentInfo): Department {
    val pair: Pair<User, Department> = parZipOrAccumulate(
        // 合并两个错误列表
        { e1: Nel<ApplicationError>, e2: Nel<ApplicationError> -> e1 + e2 },
        // 适配getUser的上下文,把单个错误包装成Nel
        { 
            raise.withRaise({ err -> Nel.of(err) }) {
                getUser(param.userLegalId)
            }
        },
        // 同理适配getDepartment的上下文
        { 
            raise.withRaise({ err -> Nel.of(err) }) {
                getDepartment(param.departmentCode)
            }
        }
    ) { a, b -> Pair(a, b) }

    saveUserDrivenPort.save(pair.first.copy(departmentId = param.departmentCode))
    return pair.second
}

优化:抽成扩展函数让代码更简洁

如果需要多次做这种转换,咱们可以把逻辑抽成一个扩展函数,避免重复代码:

// 定义扩展函数,把单个错误的Raise上下文适配成Nel错误的上下文
context(Raise<Nel<E>>)
suspend fun <E : Throwable, A> context(Raise<E>) suspend () -> A.toNelRaise(): A =
    raise.withRaise({ Nel.of(it) }) { this() }

之后调用的时候就可以简化成:

context(Raise<Nel<ApplicationError>>)
override suspend fun execute(param: AddUserToDepartmentInfo): Department {
    val pair: Pair<User, Department> = parZipOrAccumulate(
        { e1, e2 -> e1 + e2 },
        { getUser(param.userLegalId).toNelRaise() },
        { getDepartment(param.departmentCode).toNelRaise() }
    ) { a, b -> Pair(a, b) }

    saveUserDrivenPort.save(pair.first.copy(departmentId = param.departmentCode))
    return pair.second
}

这样代码看起来清爽多了,而且完全符合你的需求——并行调用两个函数,同时把各自的错误累积成一个非空列表。

备注:内容来源于stack exchange,提问作者codependent

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 14:28:12