Different `map` behavior in `test` and `dev` configs

I ran this code in test

pub fn squared(numbers: &mut [i32]) -> Vec<i32> {
    numbers.iter().map(|x| x * x).collect()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn empty() {
        let mut s = vec![];
        squared(&mut s);
        assert_eq!(s, vec![]);
    }

    #[test]
    fn one() {
        let mut s = [2];
        squared(&mut s);
        assert_eq!(s, [4]);
    }

    #[test]
    fn multiple() {
        let mut s = vec![2, 4];
        squared(&mut s);
        assert_eq!(s, vec![4, 16]);
    }
}

And got an assert_eq failure, saying this:

thread 'tests::multiple' panicked at src/lib.rs:27:9:
assertion `left == right` failed
  left: [2, 4]
 right: [4, 16]
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- tests::one stdout ----

thread 'tests::one' panicked at src/lib.rs:20:9:
assertion `left == right` failed
  left: [2]
 right: [4]


failures:
    tests::multiple
    tests::one

But when I ran this (quite similar) code in dev:

// same function!
pub fn squared(numbers: &mut [i32]) -> Vec<i32> {
    numbers.iter().map(|x| x * x).collect()
}

fn main() {
    println!("{:?}", squared(&mut [2]));
    println!("{:?}", squared(&mut [2, 4]));
}

it gives this:

[4]
[4, 16]

Why is there different behavior?

In the first code, you are writing tests that compare the input to the expected output. In the second code you are printing the output (which does correspond to the expected output from the first code). You should compare the output of the function to the expected output, either calling the function inside the assert_eq or storing it to compare later.

Also, note that your function doesn't need to take a &mut, since it is only iterating over immutable references and collecting the result into a new Vec.

squared does not mutate the input but instead returns a new vector with the mapped values.

This does nothing to s and just throws away result of the squared call.

This actually uses the return value of squared, printing it.

squared should be written to take a non-mut reference if the intention is not to mutate it. Alternatively, if squared is supposed to mutate the slice in-place, it should not use map or collect and should not return a vector but perhaps look something like this:

// "squareD" would be a misleading name
pub fn square(numbers: &mut [i32]) {
    numbers.iter_mut().for_each(|x| *x = x * x);
}
3 Likes