Я могу понять, почему этот код не компилируется:
use std::{rc::{Rc, Weak}, cell::RefCell};
struct Container {
list: Vec<Box<usize>>,
this: Weak<RefCell<Self>>,
}
impl Container {
fn new() -> Rc<RefCell<Self>> {
let res = Rc::new(RefCell::new(Self {
list: vec![],
this: Weak::new(),
}));
{
let this = Rc::downgrade(&res);
let mut ref_on_res = res.borrow_mut();
ref_on_res.this = this;
}
res
}
fn register(&mut self, v: usize) -> NumRef {
let i = self.list.len();
self.list.push(Box::new(v));
NumRef::new(Weak::clone(&self.this), i)
}
fn get(&mut self, index: usize) -> &'static mut usize {
let elt = &mut self.list[index];
Box::as_mut(elt)
}
}
struct NumRef {
c: Weak<RefCell<Container>>,
i: usize,
}
impl NumRef {
fn new(c: Weak<RefCell<Container>>, i: usize) -> Self {
Self { c, i }
}
fn get(&mut self) -> &'static mut usize {
let c = self.c.upgrade().unwrap();
c.borrow_mut().get(self.i)
}
}
fn main() {
let c = Container::new();
let mut r = c.borrow_mut().register(1234);
{
let v = r.get();
*v += 1;
}
{
assert_eq!(c.borrow().list[0], Box::new(1235));
}
}
Я могу понять, что &mut self.list[index]
в строке 34 не переживет self.list
.
Но в строке 26 Box::as_mut(elt)
должна 'static
причина жизни T
жить в куче с Box<T>
.
Компилятор говорит, что &mut self.list[index]
должен жить до тех пор, пока Box::as_mut(elt)
, и я не понимаю, почему Box::as_mut(elt)
является ссылкой на элемент, который находится в куче.
Где я ошибаюсь?
Кроме того, чтобы ответить на ваш вопрос более прямо, поскольку Box
может быть Drop
ped, вы не можете гарантировать, что ваш указатель указывает на ожидаемую память (после сброса память освобождается!).
Например: что произойдет, если Container
удалит и отбросит значение, на которое у вас есть изменяемая ссылка? Это не может быть гарантировано 'static
, потому что Container
не 'static
.
'static
просто говорит: «Пока я в прицеле, мое указанное местоположение не изменится. Меня могут уронить, что сделает недействительным мое указанное воспоминание, но я не буду двигаться».
@MeetTitan, как Box, который выделен в куче, с указателем, который находится в куче и который не изменится (указатель не изменится).
Нет, не как коробка. Здесь не имеет значения, где выделена память. Я предлагаю прочитать о жизни. Время жизни — это не то, как долго «живет» память, время жизни — это то, как долго память «находится» по определенному адресу; так что вы можете предсказать и избежать висячих указателей во время компиляции.
Box<T>
действительно похож на&'static T
?
Нет. Содержимое Box
не обязательно живет в течение жизни программы, оно живет только до тех пор, пока существует Box
, что часто намного короче.
Возврат &'static T
из &mut self
означает, что возвращаемая ссылка всегда действительна, но в данном случае это не так. Он связан с жизнью Box
и, следовательно, с жизнью self
.
fn get(&mut self, index: usize) -> &mut usize { ...
или с явно аннотированным временем жизни:
fn get<'a>(&'a mut self, index: usize) -> &'a mut usize { ...
Ваша функция возвращает
&mut usize
, что не является коробочным значением. Вы также заимствуете у&'a self
, чтобы вернуть&' static T
, что не сработает, потому что тогда указатели не могут быть гарантированно действительными. Попробуйте вернутьBox<usize>
и поискатьBorrowMut
вVec
.