提问人:Alex Lamaison 提问时间:11/2/2023 更新时间:11/2/2023 访问量:32
访客闭合中的 Kotlin 序列产量
Kotlin sequence yield in a visitor closure
问:
我正在尝试在序列中使用 yield 来延迟发出来自访问者的项目,但我收到错误“只能在协程体中调用暂停函数”。
我不是想在这里暂停,只是发出一个项目:
private fun flatten(x: MyType): Sequence<MyType> {
return sequence {
x.accept(object : MyType.Visitor {
override fun visit(a: MyType.SubTypeA) {
[email protected](a)
}
override fun visit(b: MyType.SubTypeB) {
[email protected](b)
}
override fun visit(c: MyType.SubTypeC) {
[email protected](c)
}
})
}
}
我怀疑闭包混淆了编译器,所以我添加了,但它没有帮助。我做错了什么?this@sequence
答:
1赞
Sweeper
11/2/2023
#1
我不是想在这里暂停
你是。该方法需要挂起以使序列延迟。如果它没有挂起,当您尝试使用序列的第一个元素时,将访问所有内容并立即产生所有内容。yield
accept
当您尝试获取序列的元素时,lambda 中的代码将运行,直到被调用。它会暂停 lambda 的执行,并返回所需的元素。lambda 不会继续运行,直到您尝试获取下一个元素。sequence
yield
所以如果你不能暂停,你就不能懒惰地这样做。使用类似的东西来代替。MyType.Visitor
buildList
访问者方法不仅需要挂起,还必须扩展 。这是因为使用限制悬架。这个想法是,当挂起 lambda 时,你必须继续传递,以跟踪你正在生成的序列。SequenceScope
sequence
sequence
SequenceScope
因此,所有方法以及方法都需要挂起,并且需要是 的扩展。visit
accept
SequenceScope<MyType>
class MyType {
suspend fun SequenceScope<MyType>.accept(visitor: Visitor) {
with(visitor) {
visit(a = something)
visit(b = somethingElse)
// etc...
// note that if you want to write a receiver for these visit calls,
// you should write this@accept (i.e. the sequence scope) as the receiver, not "visitor"
}
}
}
这些方法的声明如下:visit
suspend fun SequenceScope<MyType>.visit(a: MyType.SubTypeA)
在 中,您需要用 :sequence
x
with
with(x) {
accept(object: MyType.Visitor { ... })
}
如果你真的想走这条路,你可能应该添加一个新的 、 和 ,而不是修改现有的方法,这样它仍然可以以非挂起的方式使用。SuspendVisitor
acceptSuspend
评论