使用 Kotlin 和 Arrow 构建函数结果集合,而不使用可变集合

问题描述 投票:0回答:1

我有一个棘手的问题。我有一个 Kotlin 函数,它接受三个数据集合,表示需要“删除”、“更新”或“添加”的项目。对于这三个数据集中的每一个,我都会迭代,调用相应的函数来执行 CRUD 操作。虽然 CRUD 函数有不同的实现,但它们都返回一个 arrow-kt 'Either',(https://apidocs.arrow-kt.io/arrow-core/arrow.core/-either/index.html)表示函数的结果。

事情变得棘手的是,我想保留所有“剩余”(失败)结果的运行列表,以便我可以将错误编译成用户报告。最简单的解决方案,也是我当前正在使用的解决方案,是拥有一个可变的错误列表,我可以在调用每个函数时将其添加到其中。它确实有效,但并不是一种非常“实用”的做事方式。我觉得必须有一种更好的方法来使用函数式编程来避免可变集合。有什么想法吗?

更新:

我找到了“mapOrAccumulate”库函数。它很接近,但不完全是我需要的。它将返回错误或成功,但我需要一些可以给我两者的东西。

作为参考,这是我现有代码的简化版本:

fun executeNightlyUpdate(toDelete:List,toAdd:List,toUpdate:List):List<Throwable>
{
    val j = dp.journalFactory()
    val errors = mutableListOf<Throwable>()

    toDelete.forEach { addressId ->
                deletePhoneLocation(dp, addressId).onLeft {
                    it.message?.let { it1 -> j.error(it1, it) }
                    errors.add(it)
                }
            }

    toUpdate.forEach { requestPair ->
                val( id, data) = requestPair
                findOrCreateEmergencyAddress(dp, incomingData.site_id, data.company_address).onLeft{
                    it.message?.let { it1 -> j.error(it1, it)}
                    errors.add(it)
                }
            }

    sendPhoneLocations( dp, BatchAddLocation.LocationsRequest(toAdd, incomingData.site_id) ).onLeft{
                    error->
                if (error is BatchLocationError) {
                    val errorMap: Map<String, Any>? = error.requestData.serializeToMap(dp.json.value())

                    val data = errorMap?.get(error.fieldName)
                    errors.add( "Location " + error.requestData.display_name + " failed to upload. Cause: " + error.message + " field: " + error.fieldName + "  value: " + data + "")
                }
            }

    return errors.toList()
}
kotlin collections functional-programming arrow-kt
1个回答
0
投票

我可能无法提供完全有效的解决方案,但听起来您唯一需要的就是创建一个列表,然后过滤它们以查找失败的结果。一些类似的东西:

val results = toDelete.map { addressId -> deletePhoneLocation(dp, addressId) }
    + toUpdate.map { requestPair -> ... }
    + listOf(sendPhoneLocations( dp, BatchAddLocation.LocationsRequest(toAdd, incomingData.site_id)))

val errors = results.filterIsInstance<Either.Left>()
    .map { it.value }

我跳过了对

toAdd
的特殊处理,因为它看起来不正确。您创建一个可抛出列表,然后向其中添加一个字符串(?)。如果您需要这种特殊处理,您必须例如通过映射结果来添加它。

© www.soinside.com 2019 - 2024. All rights reserved.