gpt4 book ai didi

iterator - Rust 检查迭代器 : cannot borrow `*` as immutable because it is also borrowed as mutable

转载 作者:行者123 更新时间:2023-11-29 08:14:35 28 4
gpt4 key购买 nike

为什么我不能在 inspect 期间push 到这个 vector 并在 skip_while 期间对其执行contains

我已经为自己的结构 Chain 实现了自己的迭代器,如下所示:

struct Chain {
n: u32,
}

impl Chain {
fn new(start: u32) -> Chain {
Chain { n: start }
}
}

impl Iterator for Chain {
type Item = u32;

fn next(&mut self) -> Option<u32> {
self.n = digit_factorial_sum(self.n);
Some(self.n)
}
}

现在,当迭代器生成唯一值时,我想做的是 take。所以我正在检查-ing 链并推送到一个向量,然后在 take_while 范围内检查它:

let mut v = Vec::with_capacity(terms);
Chain::new(i)
.inspect(|&x| {
v.push(x)
})
.skip_while(|&x| {
return v.contains(&x);
})

但是,Rust 编译会报出这个错误:

error: cannot borrow `v` as immutable because it is also borrowed as mutable [E0502]
...
borrow occurs due to use of `v` in closure
return v.contains(&x);
^
previous borrow of `v` occurs here due to use in closure; the mutable borrow prevents subsequent moves, borrows, or modification of `v` until the borrow ends
.inspect(|&x| {
v.push(x)
})

显然我不明白“借”这个概念。我做错了什么?

最佳答案

这里的问题是您试图创建对同一变量的可变引用和不可变引用,这违反了 Rust 借用规则。而 rustc 实际上确实非常清楚地向您说明了这一点。

let mut v = Vec::with_capacity(terms);
Chain::new(i)
.inspect(|&x| {
v.push(x)
})
.skip_while(|&x| {
return v.contains(&x);
})

在这里,您尝试在两个闭包中使用 v,第一个在 inspect() 参数中,第二个在 skip_while() 参数中。非 move 闭包通过引用捕获它们的环境,因此第一个闭包的环境包含 &mut v,第二个闭包的环境包含 &v .闭包是在同一个表达式中创建的,所以即使保证 inspect()skip_while() 之前运行并删除了借用(我不是实际情况,因为这些是迭代器适配器,它们在迭代器被使用之前根本不会运行),由于词法借用规则,这是被禁止的。

不幸的是,这是借用检查器过于严格的例子之一。你可以做的是使用 RefCell ,它允许通过共享引用进行修改,但引入了一些运行时成本:

use std::cell::RefCell;

let mut v = RefCell::new(Vec::with_capacity(terms));
Chain::new(i)
.inspect(|x| v.borrow_mut().push(*x))
.skip_while(|x| v.borrow().contains(x))

认为有可能避免 RefCell 的运行时惩罚并使用 UnsafeCell相反,因为当迭代器被消耗时,这些闭包只会一个接一个地运行,而不是同时运行,所以永远不应该同时存在一个可变引用和一个不可变引用。它可能看起来像这样:

use std::cell::UnsafeCell;

let mut v = UnsafeCell::new(Vec::with_capacity(terms));
Chain::new(i)
.inspect(|x| unsafe { (&mut *v.get()).push(*x) })
.skip_while(|x| unsafe { (&*v.get()).contains(x) })

但我可能错了,无论如何,RefCell 的开销并没有那么高,除非这段代码运行在一个真的紧密循环中,所以你应该只使用UnsafeCell 作为最后的手段,只有在没有其他方法时才使用,并且在使用它时要格外小心。

关于iterator - Rust 检查迭代器 : cannot borrow `*` as immutable because it is also borrowed as mutable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36511683/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com