Search code examples
rustrust-itertools

Modulo operator in a match expression


I need to partition a given vec of numbers into odds and evens. To do that I'm using itertools crate to perform the partition like below. Since modulo(%) operator by 2 can possibly return -1, 0, 1, rust compiler still throws an error to include patterns of i32::MIN..=-2_i32 and 2_i32..=i32::MAX, which is kind of not good looking. I can overcoome this issue by including the _ pattern, but would like to know a better way to handle this kind of scenario.

use itertools::{Either, Itertools}; // 0.14.0;

fn print(nums: &Vec<i32>) {
    for num in nums {
        print!("{}, ", num);
    }

    println!();
}

fn main() {
    let nums = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    print(&nums);
    let (evens, odds): (Vec<_>, Vec<_>) = nums.iter()
                .partition_map(|num| match num % 2 {
                    0 => Either::Left(num),
                    1 | -1 => Either::Right(num),
                    _ => todo!(),
                });

    print(&nums);
    print(&evens);
    print(&odds);
}

This could be a problem in case of code coverage related stuff, since _ pattern never going to be executed no matter what's the input


Solution

  • There's really only two primary solutions here:

    1. Use _ for one of the arms so that you don't need a third:

      match num % 2 {
          0 => Either::Left(num),
          _ => Either::Right(num),
      }
      
    2. As you've said, add an extra _ arm. In these situations, you can use unreachable!() -- indeed, this is one of the documented uses for it.

      match num % 2 {
          0 => Either::Left(num),
          -1 | 1 => Either::Right(num),
          _ => unreachable!(),
      }
      

    I would consider either of these options idiomatic. Note that while the compiler doesn't know that the _ arm cannot be reached, the optimizer does and will elide that arm.