Я пытаюсь определить структуру, которая может выступать в качестве итератора для Vec
, который хранится внутри RefCell
:
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
, которая содержит как Ref
(чтобы сохранить неизменяемый RefCell
заимствованный живой), так и Iter
(для сохранения состояния итератора для next()
, а не катив мой собственный итератор для Vec
или любого другого контейнера), когда вторая выведена из (и содержит ссылку, полученную из) первой?
Я попробовал несколько подходов к реализации этого, и все запустили проверку чека. Если я помещаю обе части состояния в виде простых элементов структуры, например
struct HoldsVecInRefCellIter<'a> {
vec_ref: Ref<'a, Vec<i32>>,
vec_iter: Iter<'a, i32>,
}
то я не могу инициализировать оба поля сразу с синтаксисом HoldsVecInRefCellIter { ... }
(см., например, Есть ли у Rust синтаксис для инициализации поля структуры с более ранним полем?). Если я попытаюсь отключить последовательную инициализацию с помощью структуры типа
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
}
}
то я беру на себя измененный самозахват структуры, который не позволяет вернуть его из iter()
. Это самозахват структуры также может произойти, если вы попытаетесь сохранить ссылку на одну часть структуры в самой структуре (Почему я не могу сохранить значение и ссылку на это значение в той же структуре?), что предотвратит безопасное перемещение экземпляров структуры. Для сравнения, это похоже на структуру типа HoldsVecInRefCellIter
, если вы можете завершить инициализацию, выполнит правильную вещь при перемещении, так как все ссылки внутренне относятся к данным в другом месте, которые переживают эту структуру.
Есть трюки, чтобы избежать создания самореференций с помощью Rc
(см. примеры в https://internals.rust-lang.org/t/self-referencing-structs/418/3), но я не как они могут применяться, если вы хотите сохранить существующую структуру Iterator
, которая реализована для прямой ссылки на базовый контейнер, а не на Rc
.
Как новичок Rust из С++, это похоже на проблему, которая часто возникала ( "У меня есть логика инициализации сложного состояния в блоке кода, и я хочу отвлечь эту логику и удерживать полученное состояние в структура для использования" ).
Связанный вопрос: Возвращение итератора Vec в RefCell