How can I get a mutable reference to an item found in a vector?
I've tried the following which works if I don't make the iterator mutable using .iter():
fn main() {
let mut vec = vec![1, 2, 3, 4];
let mut wrong = -1;
let working = match vec.iter().find(|&c| *c == 2) {
Some(c) => c,
None => &wrong
};
println!("Result: {}", working);
}
But when I try to get a mutable reference using a mutable iterator .iter_mut(),
fn main() {
let mut vec = vec![1, 2, 3, 4];
let mut wrong = -1;
let mut error = match vec.iter_mut().find(|&c| *c == 2) {
Some(c) => c,
None => &mut wrong
};
println!("Result: {}", error);
}
I get the following error:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:5:48
|
5 | let mut error = match vec.iter_mut().find(|&c| *c == 2) {
| ^-
| ||
| |hint: to prevent move, use `ref c` or `ref mut c`
| cannot move out of borrowed content
I also tried to make the type in the closure mutable with |&mut c| but that gives the following error:
error[E0308]: mismatched types
--> src/main.rs:5:48
|
5 | let mut error = match vec.iter_mut().find(|&mut c| *c == 2) {
| ^^^^^^ types differ in mutability
|
= note: expected type `&&mut {integer}`
found type `&mut _`
= help: did you mean `mut c: &&&mut {integer}`?
Rust's .find passes the callback the type &Self::Item, and since you are using .iter_mut(), you've created an iterator where each item is &mut T. That means the type passed to your find callback is &&mut T. To get that to typecheck, you can do either
vec.iter_mut().find(|&&mut c| c == 2)
or
vec.iter_mut().find(|c| **c == 2)
with the second one being preferable.
The error you are getting is because the middle-ground you've chosen by using &c would set c to a value of &mut T, and one of Rust's big rules is that multiple things can't own a mutable reference to an item at the same time. Your non-mutable case works because you are allowed to have multiple immutable references to an item.
Related
Let's say I have this code:
let mut s = "hi".to_string();
let c = || s.push_str(" yo");
c();
It doesn't compile and generates this error:
error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
--> src\test.rs:120:9
|
119 | let c = || s.push_str(" yo");
| - - calling `c` requires mutable binding due to mutable borrow of `s`
| |
| help: consider changing this to be mutable: `mut c`
120 | c();
| ^ cannot borrow as mutable
For more information about this error, try `rustc --explain E0596`.
error: could not compile `test` due to previous error
Why c(); cannot borrow as mutable? It cannot borrow what as mutable? c? In order to make it work, I have to change it to:
let mut s = "hi".to_string();
let mut c = || s.push_str(" yo");
c();
But here I'm just defining a closure c. I'll not modify it, like c = || x;. Why must define it as let mut c?
But here I'm just defining a closure c. I'll not modify it, like c = || x;. Why must define it as let mut c?
Because a closure is fundamentally a structure, each captured item being a member of that structure.
So your code is roughly equivalent to this:
struct S<'a>(&'a mut String);
impl S<'_> {
fn call(&mut self) {
self.0.push_str("yo");
}
}
fn main() {
let mut s = "hi".to_string();
let c = S(&mut s);
c.call();
}
And that fails to compile with more or less the same error:
error[E0596]: cannot borrow `c` as mutable, as it is not declared as mutable
--> src/main.rs:14:5
|
13 | let c = S(&mut s);
| - help: consider changing this to be mutable: `mut c`
14 | c.call();
| ^^^^^^^^ cannot borrow as mutable
Now you might object that that's because I defined fn call(&mut self), but if you don't you get the internal part of the same error:
error[E0596]: cannot borrow `*self.0` as mutable, as it is behind a `&` reference
--> src/main.rs:8:9
|
7 | fn call(&self) {
| ----- help: consider changing this to be a mutable reference: `&mut self`
8 | self.0.push_str("yo");
| ^^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
That is you can't modify an &mut through an &. Because if you did you could create multiple &s to the same &mut through which you could modify the pointee, and that would essentially give you multiple &mut.
Which is not allowed by Rust's semantics:
At any given time, you can have either one mutable reference or any number of immutable references.
It may not look like c needs to be mutable because you aren't modifying c itself, but for closure types, the mut keyword is what allows it to mutate any external state. It changes the type of the closure to be a FnMut, which the docs refer to as "a mutably capturing closure".
It's about ownership. mut here does not mean that you will mutate c, but that you require mut-level access to the closure in order to execute it.
c borrows s mutably. This should be fairly obvious, because calling c() modifies s.
Now imagine if c would be usable without mut:
let mut s = "hi".to_string();
let c = || s.push_str(" yo");
let c1 = &c;
let c2 = &c;
c1();
c2();
Here, both c1 and c2 would have mutable access to s simultaneously, which is not possible according to Rusts borrowing rules. This is prevented automatically by the compiler, as it changes the type of the closure to FnMut as soon as you access a variable mutably from within the closure.
Then, you need mut access to the closure to execute it and the case becomes a compiler error:
let mut s = "hi".to_string();
let mut c = || s.push_str(" yo");
let c1 = &mut c;
let c2 = &mut c;
c1();
c2();
error[E0499]: cannot borrow `c` as mutable more than once at a time
--> src/main.rs:5:10
|
4 | let c1 = &mut c;
| ------ first mutable borrow occurs here
5 | let c2 = &mut c;
| ^^^^^^ second mutable borrow occurs here
6 |
7 | c1();
| -- first borrow later used here
I am trying to write quick sort in Rust, I got it working when I used the specific type [i32] but I get an error when I try to use [T].
fn main() {
let mut arr = vec![4,3,2,1];
quick_sort(&mut arr);
println!("{:?}", arr);
}
fn partition<T: Ord>(slice: &mut [T]) -> usize {
let end = slice.len() - 1;
let pivot = slice[end];
let mut j = 0;
for i in 0..end {
if slice[j] <= pivot {
slice.swap(i, j);
j += 1;
}
}
slice.swap(end, j);
j
}
fn quick_sort<T: Ord>(slice: &mut [T]) {
if !slice.is_empty() {
let j = partition(slice);
let len = slice.len();
quick_sort(&mut slice[0..j]);
quick_sort(&mut slice[j+1..len]);
}
}
I get the following error:
error[E0508]: cannot move out of type `[T]`, a non-copy slice
--> src/main.rs:9:17
|
9| let pivot = slice[end];
| ^^^^^^^^^^ cannot move out of here
| move occurs because `slice[_]` has type `T`,
| which does not implement the `Copy` trait
| help: consider borrowing here: `&slice[end]`
When let pivot = &slice[end]; , I get a different error:
error[E0308]: mismatched types
--> src/main.rs:12:22
|
7| fn partition<T: Ord>(slice: &mut [T]) -> usize {
| - this type parameter
...
12| if slice[j] <= pivot {
| ^^^^^ expected type parameter `T`, found `&T`
= note: expected type parameter `T`
found reference `&T`
I cannot get this to work with [T].
We can fix the "expected type parameter T, found &T" error by changing the if to:
if &slice[j] <= pivot {
but that runs into another error:
error[E0502]: cannot borrow `*slice` as mutable because it is also borrowed as immutable
--> src/main.rs:13:13
|
9 | let pivot = &slice[end];
| ----------- immutable borrow occurs here
...
12 | if &slice[j] <= pivot {
| ----- immutable borrow later used here
13 | slice.swap(i, j);
| ^^^^^^^^^^^^^^^^ mutable borrow occurs here
This is because we are taking a reference to a value from the slice and while that reference is alive, we are calling a method that requires mutable access to the slice.
To fix this, we can inline the referencing into the if statement itself:
fn partition<T: Ord>(slice: &mut [T]) -> usize {
let end = slice.len() - 1;
let mut j = 0;
for i in 0..end {
if slice[j] <= slice[end] {
slice.swap(i, j);
j += 1;
}
}
slice.swap(end, j);
j
}
Output:
[1, 2, 3, 4]
Playground
The reason this worked for [i32] is because calling slice[end] implicitly created a copy of the value because i32 implements the Copy trait. If a type does not implement Copy, you need to either take a reference using &slice[index] or if it implements Clone, call slice[index].clone(). In this code you have a generic T which does not implement either of those.
The following code produces interesting results:
use std::thread;
fn main() {
let mut handles = Vec::new();
let mut v = vec![1, 2, 3, 4];
for x in v.chunks_exact_mut(2) {
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", x);
});
handles.push(handle);
}
for h in handles { h.join().unwrap(); }
}
error[E0597]: `v` does not live long enough
--> src/main.rs:7:14
|
7 | for x in v.chunks_exact_mut(2) {
| ^^^^^^^^^^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `v` is borrowed for `'static`
...
16 | }
| - `v` dropped here while still borrowed
Why does 'chunking' v change the lifetime? Without 'chunking' v, the code performs correctly. So why now does it throw an error?
The problem here is that thread::spawn completely decouples the lifetime from the rest, as the thread might continue to run while main is already finished.
x is a reference to a variable in main, and there is no guarantee that main lives longer than the thread.
I think what you really want here is a threading helper library like rayon, as they already solve those problems internally:
use rayon::prelude::*;
fn main() {
let mut v = vec![1, 2, 3, 4];
v.par_chunks_exact_mut(2).for_each(|x: &mut [i32]| {
let thread_id = std::thread::current().id();
println!("{:?}: Here's a vector: {:?}", thread_id, x);
});
}
ThreadId(5): Here's a vector: [1, 2]
ThreadId(2): Here's a vector: [3, 4]
Without "chunking" v, you're iterating over Vec<i32>. This iterator produces items of type i32, so, no references, no lifetimes, the requirements for thread::spawn() (specifically the 'static requirement) are met.
chunks_exact_mut(), however, is defined on slices and gives iterator over &mut [T], so it does have a reference. And since this reference refers v, which exists in main(), it is not 'static and does not work.
You can observe the same problem if you'll iterate over &v instead of v, since that iterator gives you &i32s (playground):
error[E0597]: `v` does not live long enough
--> src/main.rs:7:14
|
7 | for x in &v {
| ^^
| |
| borrowed value does not live long enough
| argument requires that `v` is borrowed for `'static`
...
16 | }
| - `v` dropped here while still borrowed
Other than that, I'd recommend using rayon as #Finomnis suggested.
This question already has an answer here:
Error while trying to borrow 2 fields from a struct wrapped in RefCell
(1 answer)
Closed 3 years ago.
Trying to get mutable references to separate fields through a MutexGuard:
struct MyObject {
pub a: i32,
pub b: i32,
}
fn func_1(mtx: &Mutex<MyObject>) {
let mut obj = mtx.lock().unwrap();
let a = &mut obj.a;
let b = &mut obj.b;
*a += 1;
*b *= 2;
}
results in an error:
error[E0499]: cannot borrow `obj` as mutable more than once at a time
--> src/main.rs:11:18
|
10 | let a = &mut obj.a;
| --- first mutable borrow occurs here
11 | let b = &mut obj.b;
| ^^^ second mutable borrow occurs here
12 |
13 | *a += 1;
| ------- first borrow later used here
This has me a bit confused. This works when obj is a simple mutable reference (&mut MyObject). I thought maybe the Deref trait was the one causing the problem, but it also works if obj is a &mut Box<MyObject>.
See it on the Rust Playground.
What am I missing?
Mutex::lock returns a RAII lock guard in addition of ways to deal with its contained value. To get its contained value as &mut (and subsequently "split borrow"), you need to:
save the guard (returned by lock) in a separate value, as the lock needs to live as long as the value is accessed.
extract the value as &mut from the guard with MutexGuard::deref_mut.
Here's an updated func_1:
use std::ops::DerefMut;
fn func_1(mtx: &Mutex<MyObject>) {
let mut guard = mtx.lock().unwrap();
let obj = guard.deref_mut();
let a = &mut obj.a;
let b = &mut obj.b;
*a += 1;
*b *= 2;
}
This question already has answers here:
Expected closure, found a different closure
(2 answers)
What is the inferred type of a vector of closures?
(1 answer)
Closed 4 years ago.
I'm trying to build a simple RPN calculator, and I've got the basics working. I'd like to make a dispatch table to implement the various calculator functions. If I were doing this in Perl, I would write something like:
my %ops = (
'+' => sub { +shift + +shift; },
'-' => sub { +shift - +shift; },
'*' => sub { +shift * +shift; },
'/' => sub { +shift / +shift; }
);
or in JavaScript:
let ops = {
"+": (a, b) => a + b,
"-": (a, b) => a - b,
"*": (a, b) => a * b,
"/": (a, b) => a / b
};
This is what I've tried so far in Rust:
use std::collections::HashMap;
fn main() {
println!("Going to call +");
let dispatch = HashMap::new();
dispatch.insert(String::from("+"), |a, b| a + b);
dispatch.insert(String::from("-"), |a, b| a - b);
let plus = dispatch.get(&String::from("+"));
println!("2 + 3 = {}", plus(2, 3));
let minus = dispatch.get(&String::from("-"));
println!("2 - 3 = {}", minus(2, 3));
}
When I try compiling, I get these errors:
error[E0308]: mismatched types
--> src/main.rs:9:40
|
9 | dispatch.insert(String::from("-"), |a, b| a - b);
| ^^^^^^^^^^^^ expected closure, found a different closure
|
= note: expected type `[closure#src/main.rs:8:40: 8:52]`
found type `[closure#src/main.rs:9:40: 9:52]`
= note: no two closures, even if identical, have the same type
= help: consider boxing your closure and/or using it as a trait object
error[E0618]: expected function, found enum variant `plus`
--> src/main.rs:12:28
|
11 | let plus = dispatch.get(&String::from("+"));
| ---- `plus` defined here
12 | println!("2 + 3 = {}", plus(2, 3));
| ^^^^^^^^^^ not a function
help: `plus` is a unit variant, you need to write it without the parenthesis
|
12 | println!("2 + 3 = {}", plus);
| ^^^^
error[E0618]: expected function, found enum variant `minus`
--> src/main.rs:15:28
|
14 | let minus = dispatch.get(&String::from("-"));
| ----- `minus` defined here
15 | println!("2 - 3 = {}", minus(2, 3));
| ^^^^^^^^^^^ not a function
help: `minus` is a unit variant, you need to write it without the parenthesis
|
15 | println!("2 - 3 = {}", minus);
| ^^^^^
What does "no two closures, even if identical, have the same type" mean? How can I make a HashMap hold a closure, and then call it?
It sounds like using Box would fix it... Like I said, I'm pretty new, and I haven't used Box. How do I get what's in the box out of the box?
There are a few orthogonal issues here. First and foremost, your hashmap is immutable. You use let instead of let mut, which is good practice, but in order to be able to insert into it, we need it to (at least initially) be let mut. If you're planning to modify the hashmap after the initial construction, you may want to let mut the dispatch variable as well.
let dispatch = {
let mut temp = HashMap::new();
temp.insert(String::from("+"), |a, b| a + b);
temp.insert(String::from("-"), |a, b| a - b);
temp
};
Now you need an explicit type for your hashmap. The two closures you've defined, as far as the compiler is concerned, are of entirely distinct types. However, they are both compatible with fn(i32, i32) -> i32, the type of binary functions on i32 (you can replace i32 with a different numerical type if you wish), so let's make the type explicit.
let dispatch = {
let mut temp: HashMap<String, fn(i32, i32) -> i32> = HashMap::new();
temp.insert(String::from("+"), |a, b| a + b);
temp.insert(String::from("-"), |a, b| a - b);
temp
};
Finally, HashMap.get returns an std::option::Option, not a direct value, so we need to unwrap it. get returns None if the key isn't found. If this was a large project, we'd handle that error appropriately, perhaps by logging it or telling the user, but for something simple like this, we simply need to use expect, which essentially tells the compiler "Yes, I know this could go horribly wrong. I'm willfully ignoring that fact." which is perfectly fine for our simple example.
let plus = dispatch.get(&String::from("+")).expect("Couldn't find +");
let minus = dispatch.get(&String::from("-")).expect("Couldn't find -");
Complete example
use std::collections::HashMap;
fn main() {
let dispatch = {
let mut temp: HashMap<String, fn(i32, i32) -> i32> = HashMap::new();
temp.insert("+".into(), |a, b| a + b);
temp.insert("-".into(), |a, b| a - b);
temp
};
let plus = dispatch["+"];
println!("2 + 3 = {}", plus(2, 3));
let minus = dispatch["-"];
println!("2 - 3 = {}", minus(2, 3));
}
Note that you can replace String with &'static str:
let dispatch = {
let mut temp: HashMap<_, fn(i32, i32) -> i32> = HashMap::new();
temp.insert("+", |a, b| a + b);
temp.insert("-", |a, b| a - b);
temp
};