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

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.

Related

return statement causes Rust to seemingly have a mutable and shared reference at the same time

I have the following code :
fn main() {
let mut v = vec![1, 2, 3];
for _ in v.iter() {
v[0] = 0;
// return;
}
}
It does not compile, and I see why, since I'm attempting to have a shared (v.iter()) and mutable (v[0] = 0) reference of v at the same time.
However, uncommenting the return statement makes this code compile, and I'm not sure why. I guess that the compiler somehow manages to know that the shared reference to v can be dropped before the mutable borrow occurs, but how exactly does it knows that ?
In this exemple, what would be the lifetimes of the two borrows of v ?
A for loop is just syntactic sugar for a loop with a manual iterator:
for x in c {
//...
}
is equivalent to:
let mut __iterator = c.into_iter();
while let Some(x) = __iterator.next() {
//...
}
So for your original code that would be:
fn main() {
let mut v = vec![1, 2, 3];
let mut __iterator = v.iter().into_iter();
while let Some(_) = __iterator.next() {
v[0] = 0;
// return;
}
}
(The call to into_iter() is redundant here, because using that with an iterator just returns itself.)
This code fails just like yours, as expected.
But if you uncomment the return, then the compiler knows that the loop never repeats, so it is transformed as if:
fn main() {
let mut v = vec![1, 2, 3];
let mut __iterator = v.iter().into_iter();
if let Some(_) = __iterator.next() {
v[0] = 0;
}
}
Now, non-lexical lifetimes (NLL) kick in, and sees that iterator is not used beyond the call to next() so it can be dropped just there. The _ does not count because it is not a real bind, but even if you wrote _x instead, NLL would drop it immediately as it is not used further. Thus v is no longer borrowed and the assignment to v[0] is perfectly safe and legal.
If you keep the original borrow of v alive it will fail again:
fn main() {
let mut v = vec![1, 2, 3];
let mut __iterator = v.iter().into_iter();
if let Some(x) = __iterator.next() {
v[0] = 0; // error! v is still borrowed
dbg!(x);
}
}
This fails with a nice explanation:
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> src/main.rs:5:9
|
3 | let mut __iterator = v.iter().into_iter();
| -------- immutable borrow occurs here
4 | if let Some(x) = __iterator.next() {
5 | v[0] = 0;
| ^ mutable borrow occurs here
6 | dbg!(x);
| - immutable borrow later used here

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.

How can you modify edge weights for a filtered Petgraph graph?

I am using an edge filter for my graph and want to update an edge weight:
use petgraph::prelude::*;
use petgraph::graph;
use petgraph::visit::{Dfs, EdgeFiltered, IntoEdges};
fn filter_edges(edge: graph::EdgeReference<u32>) -> bool {
match edge.weight() {
0 => true,
_ => false,
}
}
fn main() {
let mut graph: graph::Graph<u32, u32> = graph::Graph::new();
let a = graph.add_node(1);
let b = graph.add_node(2);
let e = graph.add_edge(a, b, 0);
let mut filtered_graph = EdgeFiltered::from_fn(&graph, filter_edges);
let mut dfs = Dfs::new(&filtered_graph, a);
while let Some(node_index) = dfs.next(&filtered_graph) {
for edge in filtered_graph.edges(node_index) {
filtered_graph.update_edge(edge.source(), edge.target(), 1);
//graph.update_edge(edge.source(), edge.target(), 1);
}
}
}
But this errors because EdgeFiltered doesn't have an update_edge function:
error[E0599]: no method named `update_edge` found for struct `EdgeFiltered<&Graph<u32, u32>, for<'r> fn(petgraph::graph::EdgeReference<'r, u32>) -> bool {filter_edges}>` in the current scope
--> src/main.rs:22:28
|
22 | filtered_graph.update_edge(edge.source(), edge.target(), 1);
| ^^^^^^^^^^^ method not found in `EdgeFiltered<&Graph<u32, u32>, for<'r> fn(petgraph::graph::EdgeReference<'r, u32>) -> bool {filter_edges}>`
If I switch to refer to the original graph instead, it has a borrow checker error (unlike Dfs, unfortunately EdgeFiltered isn't designed to let you access the original graph):
error[E0502]: cannot borrow `graph` as mutable because it is also borrowed as immutable
--> src/main.rs:21:13
|
17 | let mut filtered_graph = EdgeFiltered::from_fn(&graph, filter_edges);
| ------ immutable borrow occurs here
18 | let mut dfs = Dfs::new(&filtered_graph, a);
19 | while let Some(node_index) = dfs.next(&filtered_graph) {
| --------------- immutable borrow later used here
20 | for edge in filtered_graph.edges(node_index) {
21 | graph.update_edge(edge.source(), edge.target(), 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
Playground link for the above
Edgefiltered is pretty minimal, and doesn't really seem to have anything intended for mutable graph manipulation. Is there any way to do this with what Petgraph comes with, or will I have to write my own version of update_edge showhow?
FilteredGraph borrows the Graph, therefore you cannot get a mutable reference to the Graph as long as FilteredGraph exists.
You can re-create a FilteredGraph on each dfs.next() call to work around this, e.g. this works:
use petgraph::graph;
use petgraph::visit::{Dfs, EdgeFiltered};
fn filter_edges(edge: graph::EdgeReference<u32>) -> bool {
match edge.weight() {
0 => true,
_ => false,
}
}
fn main() {
let mut graph: graph::Graph<u32, u32> = graph::Graph::new();
let a = graph.add_node(1);
let b = graph.add_node(2);
let e = graph.add_edge(a, b, 0);
let filtered_graph = EdgeFiltered::from_fn(&graph, filter_edges);
let mut dfs = Dfs::new(&filtered_graph, a);
while let Some(node_index) = dfs.next(&EdgeFiltered::from_fn(&graph, filter_edges)) {
let mut neighbors = graph.neighbors(node_index).detach();
while let Some((edge_idx, _)) = neighbors.next(&graph) {
graph[edge_idx] = 1;
}
}
}
Note: This will take the neighbors of the given node based on the edges present in graph, not by those present in filtered_graph.
You can solve that by ditching EdgeFiltered and manually handling it in the traversal, e.g. like this:
fn main() {
let mut graph: graph::Graph<u32, u32> = graph::Graph::new();
let a = graph.add_node(1);
let b = graph.add_node(2);
let e = graph.add_edge(a, b, 0);
let mut dfs = Dfs::new(&graph, a);
while let Some(node_index) = dfs.next(&graph) {
let mut neighbors = graph.neighbors(node_index).detach();
while let Some((edge_idx, _)) = neighbors.next(&graph) {
let edge_weight = &mut graph[edge_idx];
if *edge_weight == 0 {
*edge_weight = 1;
}
}
}
}

Why do Arc and Mutex allow me to change the value of an immutable variable?

Take this example:
fn main() {
let dato = std::sync::Arc::new(std::sync::Mutex::new(1u8));
for _ in 0..3 {
let value = dato.clone();
std::thread::spawn(move || {
let v = value.lock().unwrap();
*v += 1; // <- Error
});
}
std::thread::sleep(std::time::Duration::from_secs(1u64));
println!("{:?}", dato);
}
cannot borrow immutable local variable v as mutable
I know that changing to mut works:
std::thread::spawn(move || {
let mut v = value.lock().unwrap();
*v += 1;
});
but why does this work:
let value = dato.clone();
std::thread::spawn(move || {
*value.lock().unwrap() += 1;
});
playground
value.lock().unwrap() returns a value of type MutexGuard, which has a DerefMut implementation:
impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> {
fn deref_mut(&mut self) -> &mut T { ... }
}
DerefMut::deref_mut(x) is equivalent to &mut *x; naturally, DerefMut is also used for assignments under the pointer, like in your case.
Therefore, for *v += 1 to work, v should be a mut variable - otherwise it would be impossible for DerefMut::deref_mut to be invoked at all.
*value.lock().unwrap() += 1 works because now value.lock().unwrap() is a temporary variable without an explicit binding, so Rust is free to assign its mutability automatically.
The fact that Mutex contains an UnsafeCell inside is not related to this particular thing about DerefMut directly; however, it does mean that Mutex provides something called internal mutability, i.e. it allows one to mutate its contents through a shared reference. You can read more on it in the book.

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

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);
}

Resources