Given the following struct
and impl
:
use std::slice::Iter;
use std::cell::RefCell;
struct Foo {
bar: RefCell<Vec<u32>>,
}
impl Foo {
pub fn iter(&self) -> Iter<u32> {
self.bar.borrow().iter()
}
}
fn main() {}
I get an error message about a lifetime issue:
error: borrowed value does not live long enough
--> src/main.rs:9:9
|
9 | self.bar.borrow().iter()
| ^^^^^^^^^^^^^^^^^ does not live long enough
10 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the body at 8:36...
--> src/main.rs:8:37
|
8 | pub fn iter(&self) -> Iter<u32> {
| _____________________________________^ starting here...
9 | | self.bar.borrow().iter()
10 | | }
| |_____^ ...ending here
How am I able to return and use bar
s iterator?
You cannot do this because it would allow you to circumvent runtime checks for uniqueness violations.
RefCell
provides you a way to "defer" mutability exclusiveness checks to runtime, in exchange allowing mutation of the data it holds inside through shared references. This is done using RAII guards: you can obtain a guard object using a shared reference toRefCell
, and then access the data insideRefCell
using this guard object:The key point here is that
'b
is different from'a
, which allows one to obtain&mut T
references without having a&mut
reference to theRefCell
. However, these references will be linked to the guard instead and can't live longer than the guard. This is done intentionally:Ref
andRefMut
destructors toggle various flags inside theirRefCell
to force mutability checks and to forceborrow()
andborrow_mut()
panic if these checks fail.The simplest thing you can do is to return a wrapper around
Ref
, a reference to which would implementIntoIterator
:(try it on playground)
You can't implement
IntoIterator
forVecRefWrapper
directly because then the internalRef
will be consumed byinto_iter()
, giving you essentially the same situation you're in now.