I wrote a max
function which takes a Vec
as a parameter. It works as I expected. Then I added a min
function the same as the max
function:
fn main() {
let my_array = vec![61, 14, 71, 23, 42, 8, 13, 66];
let max = max(my_array);
let min = min(my_array);
println!("Max value is {}.", max);
}
fn max(array: Vec<i32>) -> i32 {
let mut max = array[0];
for val in array {
if max < val {
max = val;
}
}
max
}
fn min(array: Vec<i32>) -> i32 {
let mut min = array[0];
for val in array {
if min > val {
min = val;
}
}
min
}
Rust reports an error if I put the same my_array
parameter on the call to min
:
error[E0382]: use of moved value: `my_array`
--> src/main.rs:4:19
|
2 | let my_array = vec![61, 14, 71, 23, 42, 8, 13, 66];
| -------- move occurs because `my_array` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
3 | let max = max(my_array);
| -------- value moved here
4 | let min = min(my_array);
| ^^^^^^^^ value used here after move
How can I write code that works?
This is an issue that very beginners to Rust will experience. As a beginner, you should read The Rust Programming Language. A lot of effort has been put into this book, especially for newcomers to Rust. This will cover many things that you will run into.
Relevant sections:
The underlying problem is that you've transferred ownership of the vector when you call max
. The value is then gone; main
no longer has it.
The simplest thing to to is to clone the vector before passing to max
. This allows main
to keep ownership of my_array
and then transfer ownership to min
on the subsequent line:
let max = max(my_array.clone());
let min = min(my_array);
This is inefficient, as neither max
nor min
need to take ownership of the vector to do their work. Cloning the Vec
also requires additional memory allocation. It's more idiomatic to pass in a slice, which is a type of reference to the data inside the Vec
:
let max = max(&my_array);
let min = min(&my_array);
fn max(array: &[i32]) -> i32 {
let mut max = array[0];
for &val in array {
if max < val {
max = val;
}
}
max
}
When iterating over a slice, you get back references to the items in the slice. With integers, we can dereference them (here using the &
in for &val in array
) and make a copy of the value.
See also:
Even better, there's no need to rewrite basic functions like this. You also assume there's always at least one value, which isn't true for an empty vector. The idiomatic solution is to use iterators:
fn main() {
let my_array = vec![61, 14, 71, 23, 42, 8, 13, 66];
let max = my_array.iter().max();
let min = my_array.iter().min();
println!("Max value is {:?}.", max);
println!("Min value is {:?}.", min);
}
This uses Iterator::min
and Iterator::max
,
which each return an Option
, as an empty slice has no minimum or maximum value.
Technically, it's a little different from your original solution, as min
and max
are Option<&i32>
; a reference to the original slice. You can get back to Option<i32>
by using Option::copied
:
fn main() {
let my_array = vec![61, 14, 71, 23, 42, 8, 13, 66];
let max = my_array.iter().max().copied();
let min = my_array.iter().min().copied();
println!("Max value is {:?}.", max);
println!("Min value is {:?}.", min);
}
Bonus information: slices, Vec
s, and arrays are all different types. It's not correct to refer to my_array
as an array at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With