![](/img/trans.png)
[英]How to avoid mutable and immutable borrow with IntoParallelIterator bound
[英]Rust Inspect Iterator: cannot borrow `*` as immutable because it is also borrowed as mutable
為什么我不能在inspect
期間push
送到這個向量並在skip_while
期間contains
它?
我為我自己的struct 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
,而迭代器產生獨特的價值觀。 所以我正在inspect
鏈並推送到一個向量,然后在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()
參數中使用v
,在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
,因為當使用迭代器時,這些閉包只會一個接一個地運行,而不是同時運行,所以永遠不應該有一個mutable和一個不可變的引用同時出類拔萃。 它可能看起來像這樣:
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
作為最后的手段,只有在沒有其他工作時才使用,並且在使用時要格外小心使用它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.