How to combine mutable and immutable borrowing inside one method? [duplicate] - rust

This question already has answers here:
How to get mutable references to two array elements at the same time?
(8 answers)
Closed last year.
This is the code:
struct Bar {
x : i8
}
struct Foo {
items : [Bar; 2]
}
impl Foo {
pub fn update(&mut self, i : i8) {
let item = &mut self.items[0];
if self.items[1].x > 0 {
item.x = i
}
}
}
It doesn't compile:
error[E0503]: cannot use `self.items[_].x` because it was mutably borrowed
--> src/lib.rs:10:12
|
9 | let item = &mut self.items[0];
| ------------------ borrow of `self.items[_]` occurs here
10 | if self.items[1].x > 0 {
| ^^^^^^^^^^^^^^^ use of borrowed `self.items[_]`
11 | item.x = i
| ---------- borrow later used here
I believe I understand why, but what is a workaround? I do need to both modify and read the same piece of data inside the same method.

Not sure what the point in what you are trying to do is, but it can be done like this:
pub fn update(&mut self, i : i8) {
if self.items[1].x > 0 {
self.items[0].x = i
}
}

Related

How do I move a vector reference into threads? [duplicate]

This question already has an answer here:
How can I pass a reference to a stack variable to a thread?
(1 answer)
Closed last month.
How do I move a vector reference into threads? The closest I get is the (minimized) code below. (I realize that the costly calculation still isn't parallel, as it is locked by the mutex, but one problem at a time.)
Base problem: I'm calculating values based on information saved in a vector. Then I'm storing the results as nodes per vector element. So vector in vector (but only one vector in the example code below). The calculation takes time so I would like to divide it into threads. The structure is big, so I don't want to copy it.
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let n = Nodes::init();
n.calc();
println!("Result: nodes {:?}", n);
}
#[derive(Debug)]
struct Nodes {
nodes: Vec<Info>,
}
impl Nodes {
fn init() -> Self {
let mut n = Nodes { nodes: Vec::new() };
n.nodes.push(Info::init(1));
n.nodes.push(Info::init(2));
n
}
fn calc(&self) {
Nodes::calc_associative(&self.nodes);
}
fn calc_associative(nodes: &Vec<Info>) {
let mut handles = vec![];
let arc_nodes = Arc::new(nodes);
let counter = Arc::new(Mutex::new(0));
for _ in 0..2 {
let arc_nodes = Arc::clone(&arc_nodes);
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut idx = counter.lock().unwrap();
// costly calculation
arc_nodes[*idx].set_length(arc_nodes[*idx].get_length() * 2);
*idx += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
}
}
#[derive(Debug)]
struct Info {
length: u32,
}
impl Info {
fn init(length: u32) -> Self {
Info { length }
}
fn get_length(&self) -> u32 {
self.length
}
fn set_length(&mut self, x: u32) {
self.length = x;
}
}
The compiler complains that life time of the reference isn't fulfilled, but isn't that what Arc::clone() should do? Then Arc require a deref, but maybe there are better solutions before starting to dig into that...?
Compiling threads v0.1.0 (/home/freefox/proj/threads)
error[E0596]: cannot borrow data in an `Arc` as mutable
--> src/main.rs:37:17
|
37 | arc_nodes[*idx].set_length(arc_nodes[*idx].get_length() * 2);
| ^^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<&Vec<Info>>`
error[E0521]: borrowed data escapes outside of associated function
--> src/main.rs:34:26
|
25 | fn calc_associative(nodes: &Vec<Info>) {
| ----- - let's call the lifetime of this reference `'1`
| |
| `nodes` is a reference that is only valid in the associated function body
...
34 | let handle = thread::spawn(move || {
| __________________________^
35 | | let mut idx = counter.lock().unwrap();
36 | | // costly calculation
37 | | arc_nodes[*idx].set_length(arc_nodes[*idx].get_length() * 2);
38 | | *idx += 1;
39 | | });
| | ^
| | |
| |______________`nodes` escapes the associated function body here
| argument requires that `'1` must outlive `'static`
Some errors have detailed explanations: E0521, E0596.
For more information about an error, try `rustc --explain E0521`.
error: could not compile `threads` due to 2 previous errors
You wrap a reference with Arc. Now the type is Arc<&Vec<Info>>. There is still a reference here, so the variable could still be destroyed before the thread return and we have a dangling reference.
Instead, you should take a &Arc<Vec<Info>>, and on the construction of the Vec wrap it in Arc, or take &[Info] and clone it (let arc_nodes = Arc::new(nodes.to_vec());). You also need a mutex along the way (either Arc<Mutex<Vec<Info>>> or Arc<Vec<Mutex<Info>>>), since you want to change the items.
Or better, since you immediately join() the threads, use scoped threads:
fn calc_associative(nodes: &[Mutex<Info>]) {
let counter = std::sync::atomic::AtomicUsize::new(0); // Changed to atomic, prefer it to mutex wherever possible
std::thread::scope(|s| {
for _ in 0..2 {
s.spawn(|| {
let idx = counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
let node = &mut *nodes[idx].lock().unwrap();
// costly calculation
node.set_length(node.get_length() * 2);
});
}
});
}

Cryptic message when dealing with Rust Option type

I have a function like the following:
pub fn process_options<T>(in_refs:& mut Vec<T>,ivals:Vec<Option<T>>) -> i32 {
let mut nones = 0;
for int in 0..ivals.len() {
if let None = ivals[int] {
nones += 1;
} else {
in_refs.push(ivals[int].unwrap());
}
}
return nones;
}
What this function does is that it:
It pushes all the some(T) from one vector to another as T. And it also records the number of none values in the first vector. As written above the code fails to compile and gives me:
error[E0507]: cannot move out of index of `Vec<Option<T>>`
--> src/functions.rs:40:26
|
40 | in_refs.push(ivals[int].unwrap());
| ^^^^^^^^^^ -------- value moved due to this method call
| |
| help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
| move occurs because value has type `Option<T>`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves value
--> /Users/yunfeichen/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:772:25
|
772 | pub const fn unwrap(self) -> T {
Which I frankly do not understand can you explain this to me?
Edit:
This question has been solved:
It turns out I just need to use a different style of for loop, Not sure why this for loop works but it does:
pub fn process_options<T>(in_refs:& mut Vec<T>,ivals:Vec<Option<T>>) -> i32 {
let mut nones = 0;
for element in ivals{
if let None = element {
nones += 1;
} else {
in_refs.push(element.unwrap());
}
}
return nones;
}

Rust assignment and use borrow at the same time

It confuses me that the error at line A has anything to do with line C, as they basically appear in different branches?
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>
}
pub fn foo(mut head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
let mut p1 = head.as_mut()?;
if let Some(p2) = p1.next.as_mut() {
if true {
p1.next = None; // A: Error here if C is not commented out
} else {
// p1.next = None; // B
p1 = p2; // C: No error on this line
}
}
head
To make things worse, the error has code E0506, suggesting an attempt is made to assign a borrowed value (p1.next). How come I cannot assign this borrowed value (which I believe is mutably borrowed) now but I can do that simply by deleting line C?
error[E0506]: cannot assign to `p1.next` because it is borrowed
--> src/remove_dup.rs:11:13
|
9 | if let Some(p2) = p1.next.as_mut() {
| ------- borrow of `p1.next` occurs here
10 | if true {
11 | p1.next = None; // A: Error happnens here if C is not commented out
| ^^^^^^^
| |
| assignment to borrowed `p1.next` occurs here
| borrow later used here

How to return a ref to a value of a vector [duplicate]

This question already has answers here:
What is the difference between `e1` and `&e2` when used as the for-loop variable?
(1 answer)
What is the purpose of `&` before the loop variable?
(2 answers)
Closed 2 years ago.
I'm trying to return a reference to a value of a newly added item to a vector in Rust. The code:
struct Element {
id: i64,
}
struct G {
v: Vec<Element>,
}
impl G {
fn add(&mut self, id: i64) -> &Element {
let new_e = Element { id };
self.v.push(new_e);
&self.v[self.v.len()]
}
}
fn main() {
let mut g = G { v: vec![] };
let &_e1 = g.add(1);
let &_e2 = g.add(2);
let &_e3 = g.add(3);
}
Repl.it: https://repl.it/repls/UprightSnowSemicolon
I get the error:
error[E0507]: cannot move out of a shared reference
--> src/main.rs:19:16
|
19 | let &_e1 = g.add(1);
| ---- ^^^^^^^^
| ||
| |data moved here
| |move occurs because `_e1` has type `Element`, which does not implement the `Copy` trait
| help: consider removing the `&`: `_e1`
And so on for _e2 and _e3.
I really want to return a reference to the newly added item inside the vector and not a copy nor an index. Is it possible?

Optionally push item to Vec or return existing item [duplicate]

This question already has an answer here:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
(1 answer)
Closed 3 years ago.
I have a function that will either return a reference to existing item from a Vec, or push a new item onto the Vec and return a reference to that existing item. I created a basic exmple that illustrates what I want to do:
struct F {
x: Vec<Vec<String>>,
}
impl F {
fn foo(&mut self, s: String) -> &[String] {
for strings in &self.x {
if strings.contains(&s) {
return &strings;
}
}
self.x.push(vec![s]);
&self.x[self.x.len() - 1]
}
}
But when I try to compile this, I get an error about lifetimes:
error[E0502]: cannot borrow `self.x` as mutable because it is also borrowed as immutable
--> src/lib.rs:13:9
|
6 | fn foo(&mut self, s: String) -> &[String] {
| - let's call the lifetime of this reference `'1`
7 | for strings in &self.x {
| ------- immutable borrow occurs here
8 | if strings.contains(&s) {
9 | return &strings;
| -------- returning this value requires that `self.x` is borrowed for `'1`
...
13 | self.x.push(vec![s]);
| ^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
I don't understand this error, because in my mind the immutable borrow on line 7 is guaranteed to no longer exist by line 13, since the function will either have returned before line 13, or the for loop will have ended, and the borrow should end with it. What am I missing?
I think this is a limitation of current borrow checker, you can do this instead:
struct F {
x: Vec<Vec<String>>,
}
impl F {
fn foo(&mut self, s: String) -> &[String] {
let ret = self.x.iter().position(|strings| strings.contains(&s));
if let Some(ret) = ret {
&self.x[ret]
} else {
self.x.push(vec![s]);
&self.x.last().unwrap()
}
}
}
Stargateur is right and the borrow checker cannot prove that your code is correct. We have to help it.
Another possibility is to use an index while iterating over the Vecs.
struct F {
x: Vec<Vec<String>>,
}
impl F {
fn foo(&mut self, s: String) -> &[String] {
for (i, strings) in self.x.iter().enumerate() {
if strings.contains(&s) {
return &self.x[i];
}
}
self.x.push(vec![s]);
self.x.last().unwrap()
}
}
(Also use slice::last instead of manually getting the index. It's more clear what you want to do).

Resources