我的问题似乎与 Rust error "cannot infer an appropriate lifetime for borrow expression" when attempting to mutate state inside a closure returning an Iterator 密切相关,但我认为这并不相同。所以,这个
use std::iter;
fn example(text: String) -> impl Iterator<Item = Option<String>> {
let mut i = 0;
let mut chunk = None;
iter::from_fn(move || {
if i <= text.len() {
let p_chunk = chunk;
chunk = Some(&text[..i]);
i += 1;
Some(p_chunk.map(|s| String::from(s)))
} else {
None
}
})
}
fn main() {}
无法编译。编译器表示无法确定 &text[..i]
的适当生命周期。这是我能想到的最小的例子。这个想法是,有一个内部状态,它是一段文本,迭代器返回从该内部状态分配的新字符串。我是 Rust 新手,所以也许这都是显而易见的,但是我如何注释生命周期以便编译?
请注意,此示例与链接的示例不同,因为这里的 point
是作为引用传递的,而这里的 text
是移动的。另外,答案已经有一年半了,所以也许有一个更简单的方法。
编辑: 添加了 p_chunk
以强调 chunk
需要在对 next
的调用中保持不变,因此不能对于闭包来说是本地的,但应该被它捕获。
最佳答案
您的代码是尝试创建 self-referential struct 的示例,其中结构是由闭包隐式创建的。由于 text
和 chunk
都移至闭包中,因此您可以将两者视为结构体的成员。由于 chunk
引用 text
中的内容,因此结果是一个自引用结构,当前的借用检查器不支持该结构。
虽然自引用结构通常由于移动而不安全,但在这种情况下它是安全的,因为 text
是堆分配的并且随后不会发生变化,也不会逃脱闭包。因此,text
的内容不可能移动,并且足够智能的借用检查器可以证明您尝试做的事情是安全的并允许闭包编译。
The answer to the [linked question] says that referencing through an
Option
is possible but the structure cannot be moved afterwards. In my case, the self-reference is created after text and chunk were moved in place, and they are never moved again, so in principle it should work.
同意 - 原则上它应该可以工作,但众所周知,当前的借用检查器不支持它。该支持需要多个新功能:借用检查器应该使用特殊情况的堆分配类型,例如 Box 或 String ,它们的移动不会影响对其内容的引用,并且这种情况也证明您没有调整大小或 mem::replace()
封闭的 String
。
在这种情况下,最好的解决方法是“显而易见”的方法:不要保留 chunk
切片,而是保留一对 usize
索引(或 Range
)并在需要时创建切片。
关于rust - 基于 lambda 的迭代器的生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67956773/