我在寻找什么流程操作员

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

假设我有 getPeople():

List<Person>
和 getStudent(ssn: String): Student

data class Person(val name: String, val ssn: String)
data class Student(val ssn: String, val grade: Char)
data class ReportCard(val name: String, val grade: Char)

我想要一张

List<ReportCard>
,但我不想等待 getStudent 形成成绩单。例如,getPeople() 返回 [("Joy", "111"), ("Tom", "123"), ("Jerry", "567")]。假设获得的成绩是:

乔伊:C 杰瑞:F 汤姆:A

我将通过 ssn 加入 Person with a Student 以在可滚动列表中形成 ReportCard,因此我希望异步填写 ReportCard 中的字段。如果发生错误,我会忽略它并继续。

每当返回成绩时发出:

[(“乔伊”, ''), (“汤姆”, ''), (“杰瑞”, '')] <--getPeople() done

[(“乔伊”, 'A'), (“汤姆”, ''), (“杰瑞”, '')] <--getStudent(Joy) done

[(“乔伊”, 'A'), (“汤姆”, ''), (“杰瑞”, 'F')] <--getStudent(Jerry) done

[(“乔伊”, 'A'), (“汤姆”, ''), (“杰瑞”, 'F')] <--getStudent(Tom) error

成绩完成后会发出另一种解决方案:

[(“乔伊”, ''), (“汤姆”, ''), (“杰瑞”, '')] <--getPeople() done

[(“乔伊”, 'A'), (“汤姆”, ''), (“杰瑞”, 'F')] <--getStudent() calls done

kotlin kotlin-flow
1个回答
0
投票

我认为没有一组简单的流运算符可以用于此目的,因此我们需要使用

flow
构建器构建一些东西来获得该功能。

此外,不存在像示例解决方案中那样的空 Char 之类的东西,因此我将使用可为空的

Char
null
来表示没有可用的等级。

假设这些是您可用的输入:

val people: Flow<List<Person>> = //...

suspend fun getGradeForSsn(ssn: String): Char? { //...

首先,为了简化流程,创建此函数的错误捕获版本:

suspend fun getGradeForSsnOrNull(ssn: String): Char? =
    try { 
        getGradeForSsn(ssn) 
    } catch (e: CancellationException) {
        throw(e)
    } catch (e: Exception) {
        null
    }

我还没有测试过这些解决方案,但也许它们可以成为您构建可行的东西的开始。

然后,对于第二种情况,您只为每个输入人员列表发出两个成绩单列表,您可以这样做:

val reportCards = people.flatMapLatest { peopleList ->
        flow {
            emit(peopleList.map { ReportCard(it.name, null) })
            val finalList = coroutineContext {
                peopleList.map { 
                    async { ReportCard(it.name, getGradeForSsnOrNull(it.ssn)) }
                }.awaitAll()
            }
            emit(finalList)
        }
    }

第一种情况比较复杂。也许是这样的:

val reportCards = people.flatMapLatest { peopleList ->
        flow {
            val reportCardsBySsn = peopleList.associate { 
                it.ssn to ReportCard(it.name, null)
            }
            emit(reportCardsBySsn.values.toList())
            coroutineContext {
                peopleList.forEach { 
                    val grade = getGradeForSsnOrNull(it.ssn)
                    if (grade != null) {
                        reportCardsBySsn[ssn] = reportCardsBySsn[ssn].copy(grade = grade)
                        emit(reportCardsBySsn.values.toList())
                    }
                }
            }
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.