Why can't I make a reference to memory inside "if"? - rust

I could make a copy of this vector, but that will take time and memory.
I could write another println, but this is just an example — instead of println there may be several loops — and it will take space and complicate the code. I could perform the conversion in main and write two versions of the function call, but changing the reference is much easier.
fn foo(mut a: &Vec<i32>) {
let mut c: Vec<i32>;
if a[0] == 0 {
c = vec![1; 3];
a = &c;
}
println!("{:?}", a);
}
fn main() {
let a: Vec<i32> = vec![0; 3];
foo(&a);
}
Error:
main.rs:9:14: 9:15 error: `c` does not live long enough
main.rs:9 a = &c;
^

The rules of lifetime in rust are quite (very) strict: if you have a reference to an object, this object must live longer than the reference, in both direction.
This means the reference must be created after the object.
In your case, a exists before c, so the assignment a = &c is invalid. A simple fix can be to create a copy of the reference after c is created and work on this copy:
fn foo(vec_ref: &Vec<i32>){
let mut c: Vec<i32>;
let mut a = vec_ref
if a[0] == 0 {
c = vec![1; 3];
a = &c;
}
println!("{:?}",a);
}
or in a more rusty way:
fn foo(vec_ref: &Vec<i32>){
let mut c: Vec<i32>;
let a = if vec_ref[0] == 0 {
c = vec![1; 3];
&c
} else {
vec_ref
};
println!("{:?}",a);
}

Related

How do I empty a slice in a RefMut<&mut [u8]>?

If I wanted to "empty" a slice normally, I could do something like this:
let mut data: &[u8] = &[1, 2, 3];
data = &[];
But I'm using a library that returns a RefMut<&mut [u8]>, and if I try to reset it the same way:
let mut data: RefMut<&mut [u8]> = account.data.borrow_mut();
data = &[];
I get told I need:
expected struct `RefMut`, found `&[_; 0]`
I try something like this:
let mut data: RefMut<&mut [u8]> = account.data.borrow_mut();
let cleared: &mut [u8] = &mut [];
let c = RefCell::new(cleared);
data = c.borrow_mut();
But then c is dropped while still borrowed. Am I going about this the wrong way?
You can use the dereference operator to write back to the RefCell.
let refcell: RefCell<&[u8]> = RefCell::new(&[1, 2, 3]);
{
let mut data = refcell.borrow_mut();
*data = &[];
// or equivalently, *refcell.borrow_mut() = &[];
}
println!("{:?}", refcell); // RefCell { value: [] }

Understanding clones borrow

I'm fairly new to rust, and still learning the rust ownership model. I'm working on a piece of code where I hold a reference to a point in the data structure. I want to store multiple copies of this data structure, where on each copy the reference point hold different values. I (tried to) solve this by creating a mutable reference to the point inside the data structure, and after each update of the reference create a clone of the original data structure.
I was able to create this simple example that is analogue to what i'm trying to do and produces the same error.
fn main() {
let mut v = vec![1, 1, 1];
let mut c = Vec::new();
for i in &mut v {
*i += 1;
c.push(v.clone());
}
println!("{:?}", v);
}
which produces the following error
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/main.rs:107:16
|
105 | for i in &mut v {
| ------
| |
| mutable borrow occurs here
| mutable borrow later used here
106 | *i += 1;
107 | c.push(v.clone());
| ^ immutable borrow occurs here
With some help of the handy rust book i was able to interpret the error message. I believe this tells me that I cannot have both a mutable, and an immutable reference that are alive at the same time. What is (or is there) an rust-idiomatic method of iteratively creating duplicates of a data structure and updating a reference within said data structure?
Edit:
The example above might be too minified and not highlight the actual problem I'm having. What would be the rust-idiomatic way to write something like the example below.
#[derive(Clone, Debug)]
enum Tree {
Leaf,
Node { l: Box<Tree>, r: Box<Tree>, },
}
fn main() {
let mut tree = Tree::Node {
l: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }),
r: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }),
};
let augmenting_trees = vec![
Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), },
Tree::Node { l: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }), r: Box::new(Tree::Leaf), },
Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Node { l: Box::new(Tree::Leaf), r: Box::new(Tree::Leaf), }), },
];
let mut trees: Vec<Tree> = Vec::new();
let leaf = find_some_leaf_in_tree(&mut tree);
for augmenting_tree in augmenting_trees {
*leaf = augmenting_tree;
trees.push(tree.clone());
}
println!("trees: {:?}", trees);
}
fn find_some_leaf_in_tree<'a>(tree: &'a mut Tree) -> &'a mut Tree {
match tree {
Tree::Leaf => tree,
Tree::Node { l, .. } => find_some_leaf_in_tree(l),
}
}
What is (or is there) an rust-idiomatic method of iteratively creating duplicates of a data structure and updating a reference within said data structure?
The general answer is “don't use a reference for the purpose you're trying to use a reference”. In this case, you have a vector, so use indices instead of references:
fn main() {
let mut v = vec![1, 1, 1];
let mut c = Vec::new();
for i in 0..v.len() {
v[i] += 1;
c.push(v.clone());
}
dbg!(v, c);
}
Note that this doesn't mean you can't use references at all. For example, the code could be written in terms of a mutable reference to v instead:
fn modify_and_snapshot(v: &mut Vec<u32>) -> Vec<Vec<u32>> {
let mut c = Vec::new();
for i in 0..v.len() {
v[i] += 1;
c.push(v.clone());
}
c
}
fn main() {
let mut v = vec![1, 1, 1];
let c = modify_and_snapshot(&mut v);
dbg!(v, c);
}
The necessary condition is that when you want to snapshot v, you don't have a mutable reference to less than all of v — you can own the whole vector or you can have a mutable reference to the whole vector, but you can't do anything with the whole of the vector while a mutable reference to part of it exists.

Mutate vector within filter

So, I have the following code successfully performing filter in vector:
let mut v1 : Vec<i32> = vec!(1,2,3);
let v2 : Vec<&mut i32> = v1.iter_mut().filter(|x| {**x == 2}).collect();
println!("{:?}", v2);
Since the type signature of the predicate in the filter function is
FnMut(&Self::Item) -> bool, I was assuming that that mutation inside
the closure will work:
let mut v1 : Vec<i32> = vec!(1,2,3);
let v2 : Vec<&mut i32> = v1.iter_mut().filter(|x| {**x = 3; **x == 2}).collect();
println!("{:?}", v2);
But the above code results in a compile error. How to fix that ? Note
that I'm playing with rust to get a better understanding, so the abpve
example doesn't make sense (usually, nobody will try to mutate
things inside filter).
You are confusing two concepts: FnMut means that a function can change its captured variables, like:
fn main() {
let v1 = vec![1, 2, 3];
let mut i = 0usize;
let v2: Vec<_> = v1
.into_iter()
.filter(|x| {
i = i + 1;
*x == 2
})
.collect();
println!("We iterate {} times and produce {:?}", i, v2);
}
This doesn't mean that every parameter of a function will be mutable.
In your code, filter() takes a &Self::Item, which is very different from the map() one that takes Self::Item. Because the real type will translate to Map<Item=&mut i32> and Filter<Item=&&mut i32>. Rust forbids you from mutating a reference if it's behind a non mutable reference:
fn test(a: &&mut i32) {
**a = 5;
}
error[E0594]: cannot assign to `**a` which is behind a `&` reference
This is because Rust follows the the-rules-of-references:
At any given time, you can have either one mutable reference or any number of immutable references.
References must always be valid.
This means you can have more than one &&mut but only one &mut &mut. If Rust didn't stop you, you could mutate a &&mut and that would poison any other &&mut.
Unfortunately the full error description of E0594 is still not available, see #61137.
Note: Avoid side effects when you use the iterator API, I think it's OK to mutate your FnMut state but not the item, you should do this in a for loop, like:
fn main() {
let mut v1 = vec![1, 2, 3];
for x in v1.iter_mut().filter(|x| **x == 2) {
*x = 1;
}
println!("{:?}", v1);
}

How to access a vector multiple times within an 'Option'?

How to access a vector within an option without Rust moving it on the first access?
fn maybe_push(v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
if let Some(v) = v_option {
for i in 0..10 {
v.push(i);
c += i;
}
} else {
for i in 0..10 {
c += i;
}
}
// second access, fails
if let Some(v) = v_option {
for i in 10..20 {
v.push(i);
c += i;
}
} else {
for i in 10..20 {
c += i;
}
}
return c;
}
fn main() {
let mut v: Vec<usize> = vec![];
println!("{}", maybe_push(Some(&mut v)));
println!("{}", maybe_push(None));
println!("{:?}", v);
}
This gives the error:
error[E0382]: use of partially moved value: `v_option`
--> src/main.rs:16:22
|
4 | if let Some(v) = v_option {
| - value moved here
...
16 | if let Some(v) = v_option {
| ^^^^^^^^ value used here after move
Using if let Some(ref mut v) = v_option { which has been suggested fails too:
error: cannot borrow immutable anonymous field `(v_option:std::prelude::v1::Some).0` as mutable
--> src/main.rs:4:21
|
4 | if let Some(ref mut v) = v_option {
| ^^^^^^^^^
error: cannot borrow immutable anonymous field `(v_option:std::prelude::v1::Some).0` as mutable
--> src/main.rs:17:21
|
17 | if let Some(ref mut v) = v_option {
| ^^^^^^^^^
Matching by value moves the value into the pattern variables. Moving makes the original value unusable, except for the very simple objects that implement the Copy trait, such as numbers. Unlike pointers in C, mutable references are not copyable, which can be seen in the following example that doesn't compile either:
let mut v = vec![1, 2, 3];
let rv = &mut v; // mutable reference to v
{
// move rv to r1, r1 now becomes the sole mutable reference to v
let r1 = rv;
r1.push(4);
}
{
let r2 = rv; // error: rv was already moved to r1
r2.push(5);
}
Rust rejects the above because it enforces the general rule prohibiting multiple mutable references to an object. Despite this particular snippet being safe, allowing multiple mutable references to the same object at the same time would make it easy to write the kind of unsafe programs that Rust is explicitly designed to prevent, e.g. those that contain data races in multithreaded code, or those that access data through an invalidated iterator. Thus the assignment let r1 = rv can only move the rv reference to r1, disallowing the let r2 = rv statement which now refers to moved variable rv.
To fix the code, we must create separate references to the reference. This will create two distinct mutable references to the original reference rather than moving the original mutable reference into an inner scope:
let mut v = vec![1, 2, 3];
let mut rv = &mut v;
{
// rr1 is a *new* mutable reference to rv - no move is performed
let rr1 = &mut rv;
rr1.push(4);
}
{
// rr2 is a *separate* new mutable reference to rv - also no move
let rr2 = &mut rv;
rr2.push(5);
}
The syntax of push invocation is the same with r1.push and rr1.push because Rust's . operator will automatically dereference any number of references.
To return to the example from the question, the reference to Vec<usize> in the Option is like the v reference above, and matching it using the Some(v) pattern moves the reference into the v pattern variable.
To fix it, the pattern must be changed as in the above example, to specify a variable that refers to the value which is itself a reference. This is achieved using the if let Some(ref mut v) syntax. As above, where the rv declaration had to be changed to mutable, this fix also requires the Option to be mutable. With those two changes, the code compiles:
fn maybe_push(mut v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
if let Some(ref mut v) = v_option {
for i in 0..10 {
v.push(i);
c += i;
}
} else {
for i in 0..10 {
c += i;
}
}
if let Some(ref mut v) = v_option {
for i in 10..20 {
v.push(i);
c += i;
}
} else {
for i in 10..20 {
c += i;
}
}
return c;
}
fn main() {
let mut v: Vec<usize> = vec![];
println!("{}", maybe_push(Some(&mut v)));
println!("{}", maybe_push(None));
println!("{:?}", v);
}
Another possibility is to use the as_mut() method to return the option content as a mutable reference to the previous content. This is conceptually equivalent to the change from let r1 = rv to let rr1 = &mut rv in the first snippet, and would allow the use of if let Some(v) pattern, where v would still be a reference to mutable reference to the vector. This also requires that v_option is declared as mutable.

Why can I call a function that accepts a reference with a reference of a reference?

As far as I know, the & symbol creates a reference. But using sum_vec with or without & will both compile. I just want to know what is happening when I do let s1 = sum_vec(&v1);. will this create a reference of a reference ?
fn main() {
// Don't worry if you don't understand how `fold` works, the point here is that an immutable reference is borrowed.
fn sum_vec(v: &Vec<i32>) -> i32 {
return v.iter().fold(0, |a, &b| a + b);
}
// Borrow two vectors and sum them.
// This kind of borrowing does not allow mutation to the borrowed.
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
// do stuff with v1 and v2
let s1 = sum_vec(v1);//This wil also complile with &. Is this optional?.
let s2 = sum_vec(v2);
// return the answer
s1 + s2
}
let v1 = vec![1, 2, 3];
let v2 = vec![4, 5, 6];
let answer = foo(&v1, &v2);
println!("{}", answer);
println!("{}", v1.len());
}
(playground)
Yes and No. Rust will create a reference to a reference (since you asked explicitly for it with the & operator), and then immediately "autoderef" it again to fit the target type. The optimizer will then eliminate that intermediate reference.

Resources