Kotlin 调用flow.single()时何时引发NosTouchElementException

Kotlin 调用flow.single()时何时引发NosTouchElementException,kotlin,kotlin-coroutines,kotlin-flow,Kotlin,Kotlin Coroutines,Kotlin Flow,假设我有这样一个API: interface Foo { val barFlow: Flow<Bar> } 根据single的文档,如果流为空,则可以抛出NoTouchElementException。然而,这让我很困惑,因为流上的终端操作将“等待”流的元素被释放。那么对single的调用如何知道流中没有元素呢?也许一个元素还没有发射出来 我的意思是在引擎盖下,对single的调用是在执行检查之前收集源流。因此,在执行null检查之前,必须至少发出1项,以便null检查永远不

假设我有这样一个API:

interface Foo {
   val barFlow: Flow<Bar>
}
根据
single
的文档,如果流为空,则可以抛出
NoTouchElementException
。然而,这让我很困惑,因为流上的终端操作将“等待”流的元素被释放。那么对
single
的调用如何知道流中没有元素呢?也许一个元素还没有发射出来

我的意思是在引擎盖下,对
single
的调用是在执行检查之前收集源流。因此,在执行null检查之前,必须至少发出1项,以便null检查永远不会成功,并且永远不会抛出
NoTouchElementException
(对于流为不可为null的类型的情况)

那么,
NoSuchElementException
是否只可能是可空类型的流

以下是
单个
的源代码:

/**
 * The terminal operator, that awaits for one and only one value to be published.
 * Throws [NoSuchElementException] for empty flow and [IllegalStateException] for flow
 * that contains more than one element.
 */
public suspend fun <T> Flow<T>.single(): T {
    var result: Any? = NULL
    collect { value ->
        if (result !== NULL) error("Expected only one element")
        result = value
    }

    if (result === NULL) throw NoSuchElementException("Expected at least one element")
    @Suppress("UNCHECKED_CAST")
    return result as T
}
/**
*终端运算符,它只等待一个值被发布。
*为空流抛出[NoTouchElementException],为流抛出[IllegalStateException]
*包含多个元素的。
*/
public suspend fun Flow.single():T{
变量结果:有吗?=NULL
收集{值->
if(result!==NULL)错误(“预期只有一个元素”)
结果=值
}
if(result==NULL)抛出NoTouchElementException(“至少应包含一个元素”)
@抑制(“未选中的_CAST”)
将结果返回为T
}

当流在不发射单个元素的情况下完成其发射时,将引发NoTouchElementException
。我现在可以想到的一个例子是,当您需要将集合转换为流源时。如果该集合是空的,并且您在该流上调用
single
,您将得到一个
NoTouchElementException

这个例子可能看起来很荒谬,但你明白了这一点:

val emptyListFlow = emptyList<Int>().asFlow()

launch {
    val data = emptyListFlow.single()
}
val-emptyListFlow=emptyList().asFlow()
发射{
val data=emptyListFlow.single()
}

当流在不发射单个元素的情况下完成其发射时,将引发NoTouchElementException
。我现在可以想到的一个例子是,当您需要将集合转换为流源时。如果该集合是空的,并且您在该流上调用
single
,您将得到一个
NoTouchElementException

这个例子可能看起来很荒谬,但你明白了这一点:

val emptyListFlow = emptyList<Int>().asFlow()

launch {
    val data = emptyListFlow.single()
}
val-emptyListFlow=emptyList().asFlow()
发射{
val data=emptyListFlow.single()
}

那么一个流有一个终点了吗?“我还以为这是一条无穷无尽的溪流呢。”汤马斯科:当然,它可能会结束。一旦完成了调用终端的协同程序,终端操作符将在下一行继续执行。那么流就结束了吗?“我还以为这是一条无穷无尽的溪流呢。”汤马斯科:当然,它可能会结束。一旦完成了调用终端的协同程序,终端操作符将在下一行继续执行。