我试图定义一个 struct ,它可以作为RefCell
中包含的Vec
的迭代器:
use std::slice::Iter;
use std::cell::Ref;
use std::cell::RefCell;
struct HoldsVecInRefCell {
vec_in_refcell: RefCell<Vec<i32>>,
}
// TODO: struct HoldsVecInRefCellIter implementing Iterator ...
impl HoldsVecInRefCell {
fn new() -> HoldsVecInRefCell {
HoldsVecInRefCell { vec_in_refcell: RefCell::new(Vec::new()) }
}
fn add_int(&self, i: i32) {
self.vec_in_refcell.borrow_mut().push(i);
}
fn iter(&self) -> HoldsVecInRefCellIter {
// TODO ...
}
}
fn main() {
let holds_vec = HoldsVecInRefCell::new();
holds_vec.add_int(1);
holds_vec.add_int(2);
holds_vec.add_int(3);
let mut vec_iter = holds_vec.iter(); // Under the hood: run-time borrow check
for i in vec_iter {
println!("{}", i);
}
}
相比之下,vec_iter
可以在main()
中在线初始化,如下所示(故意冗长):
// Elided: lifetime parameter of Ref
let vec_ref: Ref<Vec<i32>> = holds_vec.vec_in_refcell.borrow();
// Elided: lifetime parameter of Iter
let mut vec_iter: Iter<i32> = vec_ref.iter();
当第二个容器从第一个容器派生(并保存从第一个容器获得的引用)时,有没有办法定义一个实现Iterator
的 struct ,该 struct 同时保存Ref
(保持不变的RefCell
borrow 活动)和Iter
(保持next()
的迭代器状态,而不是滚动我自己的Vec
迭代器或任何其他容器)?
我try 了几种方法来实现这一点,但都与借阅判断器相冲突.如果我把两个状态都作为裸 struct 成员,比如
struct HoldsVecInRefCellIter<'a> {
vec_ref: Ref<'a, Vec<i32>>,
vec_iter: Iter<'a, i32>,
}
然后我不能用HoldsVecInRefCellIter { ... }
语法同时初始化这两个字段(例如,参见Does Rust have syntax for initializing a struct field with an earlier field?).如果我try 用类似
struct HoldsVecInRefCellIter<'a> {
vec_ref: Ref<'a, Vec<i32>>,
vec_iter: Option<Iter<'a, i32>>,
}
// ...
impl HoldsVecInRefCell {
// ...
fn iter(&self) -> HoldsVecInRefCellIter {
let mut new_iter = HoldsVecInRefCellIter { vec_ref: self.vec_in_refcell.borrow(), vec_iter: None };
new_iter.vec_iter = new_iter.vec_ref.iter();
new_iter
}
}
then I incur a mutable self-borrow of the struct that prevents returning it from iter()
. This self-borrowing of a struct can also happen if you try to store a reference to one part of a struct in the struct itself (Why can't I store a value and a reference to that value in the same struct?), which would prevent safely moving instances of the struct. By comparison, it seems like a struct like HoldsVecInRefCellIter
, if you could complete initialization, would do the correct thing when moved, since all references internally are to data elsewhere that outlives this struct.
有一些技巧可以避免使用Rc
创建自引用(参见第https://internals.rust-lang.org/t/self-referencing-structs/418/3页的示例),但如果您想存储现有的Iterator
struct ,而该 struct 的实现是为了保存对底层容器的直接引用,而不是Rc
,我不知道如何应用这些技巧.
作为来自C++的 rust 新手,这感觉起来像是一个经常出现的问题("我在代码块中有一些复杂的状态初始化逻辑,我想抽象掉那个逻辑,并将结果状态保存在 struct 中以供使用)).
Related Question: Returning iterator of a Vec in a RefCell