我尝试在一个序列中使用yield来从一个访问者那里懒洋洋地发出项目,但是我得到了错误“Suspension functions can be called only within coroutine body”。
我并不是要在这里暂停,只是发出一个项目:
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条答案
按热度按时间rqqzpn5f1#
我不是要停职
你是 *。
yield
方法需要挂起以使序列懒惰。如果它没有挂起,当你尝试消费序列的第一个元素时,accept
将访问所有内容并立即产生所有内容。当你尝试获取序列中的一个元素时,
sequence
lambda中的代码会运行,直到yield
被调用。它会 * 挂起 * lambda的执行,并返回你想要的元素。lambda不会继续运行,直到你尝试获取下一个元素。所以如果你的
MyType.Visitor
不能挂起,你就不能懒惰地这样做。使用类似buildList
的东西代替。访问者方法不仅需要挂起,它们还必须是
SequenceScope
上的扩展。这是因为sequence
使用了限制挂起。其思想是,当在sequence
lambda中挂起时,您必须继续传递SequenceScope
沿着,以跟踪您产生的序列。因此,所有
visit
方法以及accept
方法都需要挂起,并且需要是SequenceScope<MyType>
的扩展。字符串
visit
方法的声明如下:型
在
sequence
中,您需要将x
Package 为with
:型
如果你真的想走这条路,你可能应该添加一个新的
SuspendVisitor
和acceptSuspend
,而不是修改现有的方法,这样它仍然可以以非挂起的方式使用。