How should I rewrite the following code idiomatically?
The problem seems to be that traversal could be modified during action(). One solution would be to create a temporary copy of traversal inside of traverse, but that would be a burden if traversal is large.
Maybe Idiomatically access an element of a vector mutably and immutably is the canonical version of this, but I am not sure (and have not fully understood the referenced issue)?
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(&mut self, foo_idx: usize) {
// mutate self.arena[foo_idx]
}
fn traverse(&mut self) {
for i in &self.traversal {
self.action(*i);
}
}
}
current error:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:15:13
|
14 | for i in &self.traversal {
| ---------------
| |
| immutable borrow occurs here
| immutable borrow later used here
15 | self.action(*i);
| ^^^^^^^^^^^^^^^ mutable borrow occurs here
In your case, Bar has two apparently disjoint fields, so it should be possible to hold references to each of them at the same time. The problem, though, is even though action only touches arena, rust assesses the borrowing rules based on the function's prototype:
fn action(&mut self, foo_idx: usize)
which indicates that it takes a mutable borrow of self.
Here are a few possible solutions:
Inline
If the mutation being performed inside action is simple, and isn't called from anywhere else, then just do it inline inside traverse:
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn traverse(&mut self) {
for i in &self.traversal {
// mutate arena here
self.arena[*i] = Foo{};
}
}
}
Refactor
If traversal and arena are really two different things, maybe it makes more sense for them to belong to separate types, like this:
struct Foo {}
struct Baz(Vec<Foo>);
impl Baz {
fn action(&mut self, foo_idx: usize) {
self.0[foo_idx] = Foo{};
}
}
struct Bar {
traversal: Vec<usize>,
arena: Baz,
}
impl Bar {
fn traverse(&mut self) {
for i in &self.traversal {
self.arena.action(*i);
}
}
}
Associated Function
A variation on the above theme is to simply change the prototype of action so that it takes only the field it will modify as input. action is no longer a method as such - it does not take self - but is still associated with the type Bar:
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(arena: &mut Vec<Foo>, foo_idx: usize) {
arena[foo_idx] = Foo{};
}
fn traverse(&mut self) {
for i in &self.traversal {
Self::action(&mut self.arena, *i);
}
}
}
Traverse via index
Instead of iterating the traversal Vec, you can avoid taking the initial immutable borrow like this:
struct Foo {}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(&mut self, foo_idx: usize) {
// mutate self.arena[foo_idx]
}
fn traverse(&mut self) {
for traversal_idx in 0..self.traversal.len() {
let i = self.traversal[traversal_idx];
self.action(i);
}
}
}
I can think of two ways to do this (plus an easier way that's less general). The first is to destructure the struct so you aren't dealing with self anymore, but only its data. Then the data are independent so you the ownership of arena and traverse won't conflict anymore because they are independent. The disadvantage is that the function parameters get more complex.
struct Foo {
pub i: i32,
}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(arena: &mut Vec<Foo>, foo_idx: usize) {
arena[foo_idx].i += 1;
}
fn traverse(&mut self) {
let Bar { traversal, arena } = self;
for i in traversal {
Self::action(arena, *i);
}
}
}
The other way has a nicer API but is more risky: take just one value out of self (use std::mem::take or std::mem::replace) so you can reference it with no dependency on self. This is a liability is because you need to remember to put the value back in afterwards, and if you are using Result, ? can make the function return early and not execute the cleanup.
struct Foo {
pub i: i32,
}
struct Bar {
traversal: Vec<usize>,
arena: Vec<Foo>,
}
impl Bar {
fn action(&mut self, foo_idx: usize) {
self.arena[foo_idx].i += 1;
}
fn traverse(&mut self) {
let traversal = std::mem::take(&mut self.traversal);
for i in traversal.iter() {
self.action(*i);
}
self.traversal = traversal;
}
}
If your real code is only iterating as in this example, there is an easier way to solve it: change the vector to Rc<Vec<Foo>>. That way you can use Rc::clone to get a copy of the variable that's independent of self, but points at the same data.
Related
I'm trying to understand how to work with interior mutability. This question is strongly related to my previous question.
I have a generic struct Port<T> that owns a Vec<T>. We can "chain" port B to port A so, when reading the content of port A, we are able to read the content of port B. However, this chaining is hidden to port A's reader. That is why I implemented the iter(&self) method:
use std::rc::Rc;
pub struct Port<T> {
values: Vec<T>,
ports: Vec<Rc<Port<T>>>,
}
impl <T> Port<T> {
pub fn new() -> Self {
Self { values: vec![], ports: vec![] }
}
pub fn add_value(&mut self, value: T) {
self.values.push(value);
}
pub fn is_empty(&self) -> bool {
self.values.is_empty() && self.ports.is_empty()
}
pub fn chain_port(&mut self, port: Rc<Port<T>>) {
if !port.is_empty() {
self.ports.push(port)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(
self.ports.iter()
.flat_map(|p| Box::new(p.iter()) as Box<dyn Iterator<Item = &T>>)
)
}
pub fn clear(&mut self) {
self.values.clear();
self.ports.clear();
}
}
The application has the following pseudo-code behavior:
create ports
loop:
fill ports with values
chain ports
iterate over ports' values
clear ports
The main function should look like this:
fn main() {
let mut port_a = Rc::new(Port::new());
let mut port_b = Rc::new(Port::new());
loop {
port_a.add_value(1);
port_b.add_value(2);
port_a.chain_port(port_b.clone());
for val in port_a.iter() {
// read data
};
port_a.clear();
port_b.clear();
}
}
However, the compiler complains:
error[E0596]: cannot borrow data in an `Rc` as mutable
--> src/modeling/port.rs:46:9
|
46 | port_a.add_value(1);
| ^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<Port<i32>>`
I've been reading several posts etc., and it seems that I need to work with Rc<RefCell<Port<T>>> to be able to mutate the ports. I changed the implementation of Port<T>:
use std::cell::RefCell;
use std::rc::Rc;
pub struct Port<T> {
values: Vec<T>,
ports: Vec<Rc<RefCell<Port<T>>>>,
}
impl<T> Port<T> {
// snip
pub fn chain_port(&mut self, port: Rc<RefCell<Port<T>>>) {
if !port.borrow().is_empty() {
self.ports.push(port)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(
self.ports
.iter()
.flat_map(|p| Box::new(p.borrow().iter()) as Box<dyn Iterator<Item = &T>>),
)
}
// snip
}
This does not compile either:
error[E0515]: cannot return value referencing temporary value
--> src/modeling/port.rs:35:31
|
35 | .flat_map(|p| Box::new(p.borrow().iter()) as Box<dyn Iterator<Item = &T>>),
| ^^^^^^^^^----------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | temporary value created here
| returns a value referencing data owned by the current function
I think I know what the problem is: p.borrow() returns a reference to the port being chained. We use that reference to create the iterator, but as soon as the function is done, the reference goes out of scope and the iterator is no longer valid.
I have no clue on how to deal with this. I managed to implement the following unsafe method:
pub fn iter(&self) -> impl Iterator<Item = &T> {
self.values.iter().chain(self.ports.iter().flat_map(|p| {
Box::new(unsafe { (&*p.as_ref().as_ptr()).iter() }) as Box<dyn Iterator<Item = &T>>
}))
}
While this works, it uses unsafe code, and there must be a safe workaround.
I set a playground for more details of my application. The application compiles and outputs the expected result (but uses unsafe code).
You can't modify anything behind an Rc, that's correct. While this might be solved with a RefCell, you don't want to go down that road. You might come into a situation where you'd need to enforce a specific clean() order or similar horrors.
More important: your main is fundamentally flawed, ownership-wise. Take these lines:
let mut port_a = Port::new();
let mut port_b = Port::new();
loop {
// Creates an iummutable borrow of port_b with same lifetime as port_a!
port_a.chain_port(port_b);
// ...
// A mutable borrow of port_b.
// But the immutable borrow from above persists across iterations.
port_b.clear();
// Or, even if you do fancy shenanigans at least until this line.
port_a.clear();
}
To overcome this, just constrain the ports lifetime to one iteration. You currently manually clean them up anyway, so that's already what you're doing conceptually.
Also, I got rid of that recursive iteration, just to simplify things a little more.
#[derive(Clone)]
pub struct Port<'a, T> {
values: Vec<T>,
ports: Vec<&'a Port<'a, T>>,
}
impl<'a, T> Port<'a, T> {
pub fn new() -> Self {
Self {
values: vec![],
ports: vec![],
}
}
pub fn add_value(&mut self, value: T) {
self.values.push(value);
}
pub fn is_empty(&self) -> bool {
self.values.is_empty() && self.ports.is_empty()
}
pub fn chain_port(&mut self, port: &'a Port<T>) {
if !port.is_empty() {
self.ports.push(&port)
}
}
pub fn iter(&self) -> impl Iterator<Item = &T> {
let mut port_stack: Vec<&Port<T>> = vec![self];
// Sensible estimate I guess.
let mut values: Vec<&T> = Vec::with_capacity(self.values.len() * (self.ports.len() + 1));
while let Some(port) = port_stack.pop() {
values.append(&mut port.values.iter().collect());
port_stack.extend(port.ports.iter());
}
values.into_iter()
}
}
fn main() {
loop {
let mut port_a = Port::new();
let mut port_b = Port::new();
port_a.add_value(1);
port_b.add_value(2);
port_a.chain_port(&port_b);
print!("values in port_a: [ ");
for val in port_a.iter() {
print!("{} ", val);
}
println!("]");
}
}
Currently I have a struct that looks something like the following:
struct foo {
pending: HashMap<K, V>,
loaded: Vec<V>,
}
I'm trying to write a function that will load all the pending hashmap values into loaded, while deleting any values from pending if they do not meet a certain criterion, this is what I've got right now:
pub async fn load(&mut self) {
let mut rm_vector = Vec::new();
for (key, value) in self.pending.iter_mut() {
self.add_to_loaded(value).await.unwrap_or_else( |err| {
if err == Error::SomeError {
rm_vector.push(key.clone())
}
})
}
for value in rm_vector {
self.pending.remove(&value);
}
}
The issue that I am having is that I am getting a second mutable borrow error when calling the first for loop and the if statement right after. I was wondering if anybody had any suggestions how to go about fixing this without cloning the entire hashmap.
I use the following simplified code to replicate the issue.
use std::collections::HashMap;
struct Foo {
pending: HashMap<String, u32>,
loaded: Vec<u32>,
}
impl Foo {
fn add_to_loaded(&mut self, v: u32) {
self.loaded.push(v);
}
}
impl Foo {
pub fn load(&mut self) {
for _ in self.pending.iter_mut() {
self.add_to_loaded(30);
}
}
}
The cause I think is both iter_mut() and add_to_loaded(&mut) try to mutable borrow self.
I can think of two ways to go around the problem.
Option A:
Declare the field loaded as RefCell<Vec>. With it, the first parameter of add_to_loaded can be declared as an immutable reference of self and use iter() instead of iter_mut() to iterate the HashMap. There will be no mutable borrows in the for statement. In add_to_loaded, use borrow_mut() to get a mutable reference to modify the loaded field.
use std::collections::HashMap;
use std::cell::RefCell;
struct Foo {
pending: HashMap<String, u32>,
loaded: RefCell<Vec<u32>>,
}
impl Foo {
fn add_to_loaded(&self, v: u32) {
self.loaded.borrow_mut().push(v);
}
}
impl Foo {
pub fn load(&mut self) {
for _ in self.pending.iter() {
self.add_to_loaded(30);
}
}
}
Option B:
Split the two fields and the two methods into two structs.
use std::collections::HashMap;
struct Foo {
pending: HashMap<String, u32>,
}
struct Foo2 {
loaded: Vec<u32>,
}
impl Foo {
pub fn load(&mut self, f: &mut Foo2) {
for _ in self.pending.iter() {
f.add_to_loaded(30);
}
}
}
impl Foo2 {
fn add_to_loaded(&mut self, v: u32) {
self.loaded.push(v);
}
}
I have a struct that has inner mutability.
use std::cell::RefCell;
struct MutableInterior {
hide_me: 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 get_items(&self) -> &Vec<i32> {
&self.interior.borrow().vec
}
}
fn main() {
let f = Foo {
interior: RefCell::new(MutableInterior {
vec: Vec::new(),
hide_me: 2,
}),
};
let borrowed_f = &f;
let items = borrowed_f.get_items();
}
Produces the error:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:16:10
|
16 | &self.interior.borrow().vec
| ^^^^^^^^^^^^^^^^^^^^^^ temporary value 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 method body at 15:5...
--> src/main.rs:15:5
|
15 | / pub fn get_items(&self) -> &Vec<i32> {
16 | | &self.interior.borrow().vec
17 | | }
| |_____^
The problem is that I can't have a function on Foo that returns a borrowed vec, because the borrowed vec is only valid for the lifetime of the Ref, but the Ref goes out of scope immediately.
I think the Ref must stick around because:
RefCell<T> uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can claim temporary, exclusive, mutable access to the inner value. Borrows for RefCell<T>s are tracked 'at runtime', unlike Rust's native reference types which are entirely tracked statically, at compile time. Because RefCell<T> 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.
Now I could instead write a function like this that returns the entire interior:
pub fn get_mutable_interior(&self) -> std::cell::Ref<MutableInterior>;
However this potentially exposes fields (MutableInterior.hide_me in this example) that are really private implementation details to Foo.
Ideally I just want to expose the vec itself, potentially with a guard to implement the dynamic borrowing behavior. Then callers do not have to find out about hide_me.
Instead of creating a brand new type, you can use Ref::map (since Rust 1.8). This has the same result as Levans' existing answer:
use std::cell::Ref;
impl Foo {
pub fn get_items(&self) -> Ref<'_, Vec<i32>> {
Ref::map(self.interior.borrow(), |mi| &mi.vec)
}
}
You can also use new features like impl Trait to hide the Ref from the API:
use std::cell::Ref;
use std::ops::Deref;
impl Foo {
pub fn get_items(&self) -> impl Deref<Target = Vec<i32>> + '_ {
Ref::map(self.interior.borrow(), |mi| &mi.vec)
}
}
You can create a new struct similar to the Ref<'a,T> guard returned by RefCell::borrow(), in order to wrap this Ref and avoid having it going out of scope, like this:
use std::cell::Ref;
struct FooGuard<'a> {
guard: Ref<'a, MutableInterior>,
}
then, you can implement the Deref trait for it, so that it can be used as if it was a &Vec<i32>:
use std::ops::Deref;
impl<'b> Deref for FooGuard<'b> {
type Target = Vec<i32>;
fn deref(&self) -> &Vec<i32> {
&self.guard.vec
}
}
after that, update your get_items() method to return a FooGuard instance:
impl Foo {
pub fn get_items(&self) -> FooGuard {
FooGuard {
guard: self.interior.borrow(),
}
}
}
and Deref does the magic:
fn main() {
let f = Foo {
interior: RefCell::new(MutableInterior {
vec: Vec::new(),
hide_me: 2,
}),
};
let borrowed_f = &f;
let items = borrowed_f.get_items();
let v: &Vec<i32> = &items;
}
You can wrap the Vec in an Rc.
use std::cell::RefCell;
use std::rc::Rc;
struct MutableInterior {
hide_me: i32,
vec: Rc<Vec<i32>>,
}
struct Foo {
interior: RefCell<MutableInterior>,
}
impl Foo {
pub fn get_items(&self) -> Rc<Vec<i32>> {
self.interior.borrow().vec.clone() // clones the Rc, not the Vec
}
}
fn main() {
let f = Foo {
interior: RefCell::new(MutableInterior {
vec: Rc::new(Vec::new()),
hide_me: 2,
}),
};
let borrowed_f = &f;
let items = borrowed_f.get_items();
}
When you need to mutate the Vec, use Rc::make_mut to obtain a mutable reference to the Vec. If there are still other Rcs referring to the Vec, make_mut will dissociate the Rc from the other Rcs, clone the Vec and update itself to refer to that new Vec, then give you a mutable reference to it. This ensures that the value in the other Rcs doesn't suddenly change (because Rc by itself doesn't provide interior mutability).
I'm wrapping a C library that has two structs: one has a pointer to the other.
struct StructA {
void * some_mem;
};
struct StructB {
void * some_mem;
struct StructA * some_struct;
};
Both of these structs own memory, so my wrapper has constructors and destructors for both of them.
struct StructA(*mut c_void);
impl StructA {
fn new() -> Self {
StructA(c_constructor())
}
}
impl Drop for StructA {
fn drop(&mut self) {
let StructA(ptr) = self;
c_destructor(ptr);
}
}
There's also a function that takes a pointer to StructB and returns its pointer to StructA:
const struct StructA * get_struct(const struct StructB * obj);
The user of this function should not free the returned pointer, since it will be freed when the user frees obj.
How can I wrap this function? The problem is that the destructor for StructB frees all its memory, including the one for StructA. So if my wrapping of get_struct returns an object, then the wrapped StructA will be freed twice (right?). It could instead return a reference to an object, but where would that object live?
I could have separate structs for StructA based on whether it's standalone and needs to be freed or if it's a reference, but I'm hoping that's unnecessary.
I could have separate structs for StructA based on whether it's standalone and needs to be freed or if it's a reference, but I'm hoping that's unnecessary.
It's necessary. The difference between an owned StructA * and a borrowed StructA * is precisely the same as the difference between a Box<T> and a &T. They're both "just a pointer", but the semantics are completely different.
Something along these lines is probably what you want:
use std::marker::PhantomData;
struct OwnedA(*mut c_void);
impl Drop for OwnedA {
fn drop(&mut self) { }
}
impl OwnedA {
fn deref(&self) -> RefA { RefA(self.0, PhantomData) }
}
struct RefA<'a>(*mut c_void, PhantomData<&'a u8>);
struct OwnedB(*mut c_void);
impl Drop for OwnedB {
fn drop(&mut self) { }
}
impl OwnedB {
fn get_a(&self) -> RefA { RefA(get_struct(self.0), PhantomData) }
}
In particular, it's worth noting that lifetime parameter on RefA lets the compiler make sure you don't use a RefA after the backing structure has been freed.
I could have separate structs for StructA based on whether it's standalone and needs to be freed or if it's a reference, but I'm hoping that's unnecessary.
I believe this would be the accepted pattern. For backup, I'd point to the fact that this is a normal pattern in the Rust library. &str and String, &[T] and Vec<T>, Path and PathBuf, and probably lots of others I can't think of.
The good news is that you can use similar patterns as these pairs, leveraging Deref or DerefMut to call down to shared implementation:
use std::ops::{Deref, DerefMut};
enum RawFoo {}
fn c_foo_new() -> *const RawFoo { std::ptr::null() }
fn c_foo_free(_f: *const RawFoo) {}
fn c_foo_count(_f: *const RawFoo) -> u8 { 42 }
fn c_foo_make_awesome(_f: *const RawFoo, _v: bool) { }
struct OwnedFoo(Foo);
impl OwnedFoo {
fn new() -> OwnedFoo {
OwnedFoo(Foo(c_foo_new()))
}
}
impl Drop for OwnedFoo {
fn drop(&mut self) { c_foo_free((self.0).0) }
}
impl Deref for OwnedFoo {
type Target = Foo;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl DerefMut for OwnedFoo {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
struct Foo(*const RawFoo);
impl Foo {
fn count(&self) -> u8 { c_foo_count(self.0) }
fn make_awesome(&mut self, v: bool) { c_foo_make_awesome(self.0, v) }
}
fn main() {
let mut f = OwnedFoo::new();
println!("{}", f.count());
f.make_awesome(true);
}
Then, when you get a borrowed pointer from your other object, just wrap it up in a &Foo:
use std::mem;
fn c_bar_foo_ref() -> *const RawFoo { std::ptr::null() }
// Ignoring boilerplate for wrapping the raw Bar pointer
struct Bar;
impl Bar {
fn new() -> Bar { Bar }
fn foo(&self) -> &Foo {
unsafe { mem::transmute(c_bar_foo_ref()) }
}
fn foo_mut(&mut self) -> &mut Foo {
unsafe { mem::transmute(c_bar_foo_ref()) }
}
}
fn main() {
let mut b = Bar::new();
println!("{}", b.foo().count());
b.foo_mut().make_awesome(true);
// Doesn't work - lifetime constrained to Bar
// let nope = Bar::new().foo();
}
I have a struct that has inner mutability.
use std::cell::RefCell;
struct MutableInterior {
hide_me: 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 get_items(&self) -> &Vec<i32> {
&self.interior.borrow().vec
}
}
fn main() {
let f = Foo {
interior: RefCell::new(MutableInterior {
vec: Vec::new(),
hide_me: 2,
}),
};
let borrowed_f = &f;
let items = borrowed_f.get_items();
}
Produces the error:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:16:10
|
16 | &self.interior.borrow().vec
| ^^^^^^^^^^^^^^^^^^^^^^ temporary value 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 method body at 15:5...
--> src/main.rs:15:5
|
15 | / pub fn get_items(&self) -> &Vec<i32> {
16 | | &self.interior.borrow().vec
17 | | }
| |_____^
The problem is that I can't have a function on Foo that returns a borrowed vec, because the borrowed vec is only valid for the lifetime of the Ref, but the Ref goes out of scope immediately.
I think the Ref must stick around because:
RefCell<T> uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can claim temporary, exclusive, mutable access to the inner value. Borrows for RefCell<T>s are tracked 'at runtime', unlike Rust's native reference types which are entirely tracked statically, at compile time. Because RefCell<T> 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.
Now I could instead write a function like this that returns the entire interior:
pub fn get_mutable_interior(&self) -> std::cell::Ref<MutableInterior>;
However this potentially exposes fields (MutableInterior.hide_me in this example) that are really private implementation details to Foo.
Ideally I just want to expose the vec itself, potentially with a guard to implement the dynamic borrowing behavior. Then callers do not have to find out about hide_me.
Instead of creating a brand new type, you can use Ref::map (since Rust 1.8). This has the same result as Levans' existing answer:
use std::cell::Ref;
impl Foo {
pub fn get_items(&self) -> Ref<'_, Vec<i32>> {
Ref::map(self.interior.borrow(), |mi| &mi.vec)
}
}
You can also use new features like impl Trait to hide the Ref from the API:
use std::cell::Ref;
use std::ops::Deref;
impl Foo {
pub fn get_items(&self) -> impl Deref<Target = Vec<i32>> + '_ {
Ref::map(self.interior.borrow(), |mi| &mi.vec)
}
}
You can create a new struct similar to the Ref<'a,T> guard returned by RefCell::borrow(), in order to wrap this Ref and avoid having it going out of scope, like this:
use std::cell::Ref;
struct FooGuard<'a> {
guard: Ref<'a, MutableInterior>,
}
then, you can implement the Deref trait for it, so that it can be used as if it was a &Vec<i32>:
use std::ops::Deref;
impl<'b> Deref for FooGuard<'b> {
type Target = Vec<i32>;
fn deref(&self) -> &Vec<i32> {
&self.guard.vec
}
}
after that, update your get_items() method to return a FooGuard instance:
impl Foo {
pub fn get_items(&self) -> FooGuard {
FooGuard {
guard: self.interior.borrow(),
}
}
}
and Deref does the magic:
fn main() {
let f = Foo {
interior: RefCell::new(MutableInterior {
vec: Vec::new(),
hide_me: 2,
}),
};
let borrowed_f = &f;
let items = borrowed_f.get_items();
let v: &Vec<i32> = &items;
}
You can wrap the Vec in an Rc.
use std::cell::RefCell;
use std::rc::Rc;
struct MutableInterior {
hide_me: i32,
vec: Rc<Vec<i32>>,
}
struct Foo {
interior: RefCell<MutableInterior>,
}
impl Foo {
pub fn get_items(&self) -> Rc<Vec<i32>> {
self.interior.borrow().vec.clone() // clones the Rc, not the Vec
}
}
fn main() {
let f = Foo {
interior: RefCell::new(MutableInterior {
vec: Rc::new(Vec::new()),
hide_me: 2,
}),
};
let borrowed_f = &f;
let items = borrowed_f.get_items();
}
When you need to mutate the Vec, use Rc::make_mut to obtain a mutable reference to the Vec. If there are still other Rcs referring to the Vec, make_mut will dissociate the Rc from the other Rcs, clone the Vec and update itself to refer to that new Vec, then give you a mutable reference to it. This ensures that the value in the other Rcs doesn't suddenly change (because Rc by itself doesn't provide interior mutability).