Allocating struct objects on heap inside loop in rust - rust

I need to allocate structs with a drop trait inside a for loop and have a mutable reference for downstream processing. I have created this minimal example code that I can't compile with rust version 1.59. I have tried using the internal mutability with Rc and RefCell as well.
use std::cell::RefCell;
use std::rc::Rc;
// MyVec with Drop Trait
struct MyVec {
vec: Vec<i32>,
}
impl Drop for MyVec {
fn drop(&mut self) {
println!("Dropping MyVec with data `{:?}`!", self.vec);
}
}
impl MyVec {
// Get a mutable slice
fn mut_slice(&mut self) -> &mut [i32]{
return &mut self.vec[..]
}
}
pub fn test() {
// Needed for downstream purposes
let mut all_slices = Vec::new();
// Storing reference counter Rc and RefCell combo
// Hoping to prevent allocated MyVec objects from dropping and have one mutable reference
let mut all_refs = Vec::new();
for _i in 0..1 {
let my_vec = Rc::new(RefCell::new(MyVec {
vec: vec![1, 2, 3]
}));
// Make a clone of my_vec to prevent it from dropping
all_refs.push(Rc::clone(&my_vec));
let mut my_vec_mut = my_vec.borrow_mut();
let x = my_vec_mut.mut_slice();
all_slices.push(x);
}
println!("{:?}", all_slices);
}
The same code works when I unroll the loop and write the following code:
pub fn test() {
// Needed for downstream purposes
let mut all_slices = Vec::new();
// Storing reference counter Rc and RefCell combo
// Hoping to prevent allocated MyVec objects from dropping and have one mutable reference
let mut all_refs = Vec::new();
let my_vec = Rc::new(RefCell::new(MyVec {
vec: vec![1, 2, 3]
}));
// Make a clone of my_vec to prevent it from dropping
all_refs.push(Rc::clone(&my_vec));
let mut my_vec_mut = my_vec.borrow_mut();
let x = my_vec_mut.mut_slice();
all_slices.push(x);
println!("{:?}", all_slices);
}
Update: Thanks to Masklinn's comments, I fixed the code. I needed to create objects in the loop and required a mutable reference to its internal data field outside the scope of the loop. The rust compiler showed an error that the references outlive the object itself. Finally, I used a separate loop to allocate the objects and a second loop with iter_mut to create mutable references. Here is the final code:
pub fn test() {
// Needed for downstream purposes
let mut all_slices = Vec::new();
// Hoping to prevent allocated MyVec objects from dropping and have one mutable reference
let mut all_vecs = Vec::new();
for _i in 0..1 {
all_vecs.push(MyVec {
vec: vec![1, 2, 3]
});
}
for my_vec in all_vecs.iter_mut() {
all_slices.push(my_vec.mut_slice());
}
println!("{:?}", all_slices);
}

Related

How to call method on struct that has mutable self in Rust

I am having trouble with the following set up:
#[derive(Debug)]
struct SomeStruct {
numbers: Vec<u32>,
}
impl SomeStruct {
fn some_func(&mut self) { // `mut` causes the issue
self.numbers.push(9); // Contrived but need to call self in here.
println!("Hello from some func");
}
}
pub fn main() {
let struct1 = SomeStruct {
numbers: vec![1, 2, 3],
};
let struct2 = SomeStruct {
numbers: vec![99, 98, 97],
};
let mut vec = Vec::new();
vec.push(&struct1);
vec.push(&struct2);
let first = vec.first_mut().unwrap();
// cannot borrow `**first` as mutable, as it is behind a `&` reference
// cannot borrow as mutable rustc(E0596)
first.some_func();
}
There are many questions about mutable & borrowing but I still can't figure it out. Could someone please explain why this is wrong and how to fix it?
The problem is that vec only has shared references, i.e. &SomeStruct instead of SomeStruct or &mut SomeStruct.
The call to some_func() can't succeed in this setup because it requires &mut self. However, there are ways to work around this:
let vec own SomeStruct, e.g.: vec![struct1, struct2]
Push &mut struct1 and &mut struct2 in the vec
use interior mutability, e.g. through RefCell which would allow you to modify data while holding a shared reference
The interior mutability solution would look something like this:
use std::cell::RefCell;
#[derive(Debug)]
struct SomeStruct {
numbers: RefCell<Vec<u32>>,
}
impl SomeStruct {
fn some_func(&self) {
self.numbers.borrow_mut().push(9); // Contrived but need to call self in here.
println!("Hello from some func");
}
}
pub fn main() {
let struct1 = SomeStruct {
numbers: RefCell::new(vec![1, 2, 3]),
};
let struct2 = SomeStruct {
numbers: RefCell::new(vec![99, 98, 97]),
};
let mut vec = Vec::new();
vec.push(&struct1);
vec.push(&struct2);
let first = vec.first().unwrap();
// cannot borrow `**first` as mutable, as it is behind a `&` reference
// cannot borrow as mutable rustc(E0596)
first.some_func();
}

Rust cannot return value referencing local variable on HashMap get

I have a code looks like this:
use std::collections::HashMap;
fn main() {
let x = get_hash_map();
println!("{:?}", x);
}
fn get_hash_map() -> Option<&'static Vec<i32>> {
let mut hm = HashMap::new();
let mut vec = Vec::new();
vec.push(1);
hm.insert("1".to_string(), vec);
return hm.get("1");
}
But I got this error:
error[E0515]: cannot return value referencing local variable `hm`
--> src/main.rs:13:12
|
13 | return hm.get("1");
| --^^^^^^^^^
| |
| returns a value referencing data owned by the current function
| `hm` is borrowed here
Here is the rust playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7605176aee2dd3ff77a0cfd04a89db55
Can anyone suggest the alternatives to fix this problem minimally? Thanks!
fn get_hash_map() -> Option<&'static Vec<i32>> {
let mut hm = HashMap::new();
let mut vec = Vec::new();
vec.push(1);
hm.insert("1".to_string(), vec);
return hm.get("1");
}
This is invalid, because you have declared you are going to return an Option<&'static Vec<i32>>, but you are returning an Option<&'a Vec<i32>> where 'a is the current function lifetime. The HashMap will stop existing as soon as the function returns, freeing the vector, and the reference will then become dangling. This is the exact kind of situation the borrow checker is designed to avoid.
Just return the vector by value:
fn get_hash_map() -> Option<Vec<i32>> {
let mut hm = HashMap::new();
let mut vec = Vec::new();
vec.push(1);
hm.insert("1".to_string(), vec);
return hm.remove("1");
}
remove moves the value out of the map, returning it as an Option<V>.
If you then need an Option<&Vec<i32>>, you can just use as_ref() on your Option<Vec<i32>> to get one. Always remember it will become invalid as soon as its value goes out of scope.
The HashMap hm is local to the scope of the get_hash_map() function and is dropped as soon as get_hash_map() returns. The value returned by hm.get("1") contains a reference to this HashMap, thus its lifetime is also tied to the scope of get_hash_map() which unfortunately is shorter than the ascribed 'static lifetime.
If you remove the 'static lifetime and replaced it by some 'a annotation on the function, you would get a similar error, since again there is no (sound) way to return borrowed data from a function that creates the owner of that data.
You can however create the map in the surrounding scope and pass it via a mutable reference to get_hash_map
use std::collections::HashMap;
fn main() {
let mut hm = HashMap::new();
let x = get_hash_map(&mut hm);
println!("{:?}", x);
}
// note that both `hm` and the reference in the return type have the same 'a lifetime.
fn get_hash_map<'a>(hm: &'a mut HashMap<String, Vec<i32>>) -> Option<&'a Vec<i32>> {
let mut vec = Vec::new();
vec.push(1);
hm.insert("1".to_string(), vec);
hm.get("1");
}

What is a reborrow and how does it influence the code the compiler generates?

Part of the assert_eq macro code is:
($left:expr, $right:expr, $($arg:tt)+) => ({
match (&($left), &($right)) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
// The reborrows below are intentional. Without them, the stack slot for the
// borrow is initialized even before the values are compared, leading to a
// noticeable slow down.
$crate::panic!(r#"assertion failed: `(left == right)`
left: `{:?}`,
right: `{:?}`: {}"#, &*left_val, &*right_val,
$crate::format_args!($($arg)+))
}
}
}
});
The comment says that the reborrow is intentional and that it would somehow influence how stack is used.
What is a reborrow and how does it influence the code the compiler generates?
I am not sure how it affects compilation but a reborrow is when you dereference something and then borrow it straight after.
For example:
fn main() {
let mut vec: Vec<u8> = vec![1, 2, 3];
let mut_ref: &mut Vec<u8> = &mut vec;
let reborrow: &Vec<u8> = &*mut_ref;
}
It can be used to:
get an immutable reference from a mutable reference (code above)
get a reference with a shorter lifetime
get a reference to something in a smart pointer
get a reference from a pointer
and probably other things too.. (I am fairly new to Rust 😃)
Example use for shortening lifetime (very contrived but this is oversimplified):
fn main() {
let mut outer_vec = vec![1, 2, 3];
let outer_ref = &mut outer_vec;
{
// shorten lifetime of outer_ref
// not doing this causes an error
let mut outer_ref = &mut *outer_ref; // mutable reborrow
let mut inner_vec = vec![1, 2, 3];
let inner_ref = &mut inner_vec;
// imagine a real condition
if true {
outer_ref = inner_ref;
}
// use outer_ref which could point to the outer_vec or inner_vec
println!("{:?}", outer_ref);
}
println!("{:?}", outer_ref);
}
Getting a reference to something behind a smart pointer (Box in this case):
fn main() {
let vec = vec![1, 2, 3];
let boxed = Box::new(vec);
let reborrow: &Vec<u8> = &*boxed;
println!("{:?}", reborrow);
}
Reference from pointer:
fn main() {
let num: u8 = 10;
let pointer: *const u8 = &num as *const u8;
unsafe {
let ref_from_ptr: &u8 = &*pointer;
}
}
Not sure if all of these are strictly considered a "reborrow" by the way.

Borrowing mutable twice while using the same variable

Suppose that I'm going through a vector (not necessarily linearly, so I can't just use map) and I need to change an element when it satisfies some condition. I would think to use some variable to keep track of where I am, for example, something like a current variable
let mut v = vec![1, 2, 3, 4];
let mut current = &mut v[0];
and then check current to for some condition to see if it needs to be changed. However, when I do
current = &mut v[1];
It gives me the cannot borrow v as mutable more than once at a time.
I feel like this should be allowed, since I've only used one variable, and I can't access the old borrow any more.
Is there some way I can let rust know that I'm giving the first borrow back, so I'm not borrowing twice? Or have I been thinking about this wrong, and there is a different rust idiom I should use? I've solved this problem by using the indeces for the vector instead of a mutable reference, but I think this problem of "traversing using a current and then changing it" goes beyond just vectors. What if the data structure I had didn't have indeces?
The mutable reference exists until the variable goes out of scope, so you can have several mutable borrows in sequence by putting blocks around each one:
fn do_stuff(n: &mut usize) {
*n += 1;
}
fn main() {
let mut v = vec![1, 2, 3, 4];
{
let current = &mut v[1];
do_stuff(current);
}
{
let current = &mut v[0];
do_stuff(current);
}
println!("{:?}", v);
}
This is unnecessary with non-lexical lifetimes, which are currently only available on the nightly version:
#![feature(nll)]
fn do_stuff(n: &mut usize) {
*n += 1;
}
fn main() {
let mut v = vec![1, 2, 3, 4];
let mut current = &mut v[1];
do_stuff(current);
current = &mut v[0];
do_stuff(current);
println!("{:?}", v);
}
If you want to access more than one, you have to create a scope.
fn main() {
let mut vec = vec![2, 3, 5];
{
let mut current1 = vec.get_mut(1);
println!("{:?}", current1);
}
{
let mut current2 = vec.get_mut(2);
println!("{:?}", current2);
}
for i in 0..3 {
let mut current = vec.get_mut(i);
println!("{:?}", current);
}
}

How can I swap items in a vector, slice, or array in Rust?

My code looks like this:
fn swap<T>(mut collection: Vec<T>, a: usize, b: usize) {
let temp = collection[a];
collection[a] = collection[b];
collection[b] = temp;
}
Rust is pretty sure I'm not allowed to "move out of dereference" or "move out of indexed content", whatever that is. How do I convince Rust that this is possible?
There is a swap method defined for &mut [T]. Since a Vec<T> can be mutably dereferenced as a &mut [T], this method can be called directly:
fn main() {
let mut numbers = vec![1, 2, 3];
println!("before = {:?}", numbers);
numbers.swap(0, 2);
println!("after = {:?}", numbers);
}
To implement this yourself, you have to write some unsafe code. Vec::swap is implemented like this:
fn swap(&mut self, a: usize, b: usize) {
unsafe {
// Can't take two mutable loans from one vector, so instead just cast
// them to their raw pointers to do the swap
let pa: *mut T = &mut self[a];
let pb: *mut T = &mut self[b];
ptr::swap(pa, pb);
}
}
It takes two raw pointers from the vector and uses ptr::swap to swap them safely.
There is also a mem::swap(&mut T, &mut T) when you need to swap two distinct variables. That cannot be used here because Rust won't allow taking two mutable borrows from the same vector.
As mentioned by #gsingh2011, the accepted answer is no longer good approach. With current Rust this code works fine:
fn main() {
let mut numbers = vec![1, 2, 3];
println!("before = {:?}", numbers);
numbers.swap(0, 2);
println!("after = {:?}", numbers);
}
try it here

Resources