У меня есть структура, которая имеет внутреннюю изменчивость.Как вернуть ссылку на что-то внутри RefCell без нарушения инкапсуляции?
use std::cell::RefCell;
struct MutableInterior {
hideMe: i32,
vec: Vec<i32>,
}
struct Foo {
//although not used in this particular snippet,
//the motivating problem uses interior mutability
//via RefCell.
interior: RefCell<MutableInterior>,
}
impl Foo {
pub fn getItems(&self) -> &Vec<i32> {
&self.interior.borrow().vec
}
}
fn main() {
let f = Foo {
interior: RefCell::new(MutableInterior {
vec: Vec::new(),
hideMe: 2,
}),
};
let borrowed_f = &f;
let items = borrowed_f.getItems();
}
Выдает ошибку:
error: borrowed value does not live long enough
--> src/main.rs:16:10
|
16 | &self.interior.borrow().vec
| ^^^^^^^^^^^^^^^^^^^^^^ does not live long enough
17 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the body at 15:40...
--> src/main.rs:15:41
|
15 | pub fn getItems(&self) -> &Vec<i32> {
| _________________________________________^ starting here...
16 | | &self.interior.borrow().vec
17 | | }
| |_____^ ...ending here
Проблема заключается в том, что я не могу иметь функцию, которая возвращает Foo
заимствованные vec
, потому что заимствовано vec
действительна только для времени жизни Ref
, но Ref
выходит за пределы сферы действия.
Я думаю, что Ref
должен остаться because:
RefCell uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can claim temporary, exclusive, mutable access to the inner value. Borrows for RefCells are tracked 'at runtime', unlike Rust's native reference types which are entirely tracked statically, at compile time. Because RefCell borrows are dynamic it is possible to attempt to borrow a value that is already mutably borrowed; when this happens it results in task panic.
Теперь я мог бы вместо того, чтобы написать такую функцию, которая возвращает весь интерьер:
pub fn getMutableInterior(&self) -> std::cell::Ref<MutableInterior>;
Однако это потенциально подвергает поля (MutableInterior.hideMe
в этот пример), которые действительно являются частными сведениями об осуществлении до Foo
.
В идеале я просто хочу разоблачить сам vec
, потенциально с защитой для реализации поведения динамического заимствования. Затем звонящим не нужно узнавать о hideMe
.
Это единственный/идиоматических способ сделать это? Кажется, что у вас немного проблемы ... Хотя я полагаю, что вместо метода getItems() вы могли бы заимствовать внутренние элементы в блоке, где он затем выходил из области видимости (или что-то еще ...) – norcalli
@Norcalli В конкретном case 'RefCell', объект должен быть уведомлен, когда ссылка выходит за пределы области действия (это то, что делает деструктор' Ref'). Здесь нам нужно сохранить это поведение (ошибка OP была вызвана слишком ранним экземпляром 'Ref') и, таким образом, инкапсулировать его. – Levans