mmeisson
mmeisson

Reputation: 673

Is there any equivalent to JavaScript's forEach in Rust?

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

Answers (1)

Peter Hall
Peter Hall

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 Vecs that you then throw away.

Upvotes: 11

Related Questions