Reputation: 673
How do I improve this function :
use std::{env, process::exit};
fn get_grid() -> [[u8; 9]; 9] {
let mut grid: [[u8; 9]; 9] = Default::default();
let mut args: Vec<String> = env::args().collect();
if args.len() != 10 {
eprintln!("This program need 9 strings of 9 numbers between 0 and 9");
exit(1);
}
args.remove(0);
let _: Vec<_> = args
.iter()
.enumerate()
.map(|(i, arg)| {
let _line: Vec<_> = arg
.split(' ')
.enumerate()
.map(|(j, value)| match value.parse() {
Ok(x) => {
grid[i][j] = x;
x
}
Err(e) => {
eprintln!("Value {} is not a valid integer [{}]", value, e);
exit(1);
}
})
.collect();
})
.collect();
return grid;
}
As far as I understand .map()
will, when collecting, build a new iterable ( Vec
here), and return it. I don't need to have this iterable, I just want to modify an external array, and not have anything built from this iteration.
In JavaScript, there is .map
, but also a .forEach
that iterates on map
and returns nothing. Is there any equivalent in Rust?
I could probably just use a for (index, value) in args.iter().enumerate()
but I am searching a way to avoid an explicit loop, if there is one.
Upvotes: 4
Views: 10973
Reputation: 58735
For mutating an existing data structure, using an explicit loop is the most idiomatic way to do it:
for (i, arg) in args.iter().enumerate() {
for (j, value) in arg.split(' ').enumerate() {
match value.parse() {
Ok(x) => {
grid[i][j] = x;
}
Err(e) => {
eprintln!("Value {} is not a valid integer [{}]", value, e);
exit(1);
}
}
}
}
You can write this with Iterator::for_each
, but it is not likely to be considered "better" by most Rust developers:
args.iter().enumerate().for_each(|(i, arg)| {
arg.split(' ')
.enumerate()
.for_each(|(j, value)| match value.parse() {
Ok(x) => {
grid[i][j] = x;
}
Err(e) => {
eprintln!("Value {} is not a valid integer [{}]", value, e);
exit(1);
}
})
});
Regardless of which you use, you definitely should not be collecting into all those Vec
s that you then throw away.
Upvotes: 11