How do I match based on a dynamic variable?

Viewed 995

Is it possible to match on a dynamic variable instead of only literals?

In this code, the first match should do the same as the commented out match (number[0] being 0 and number[1] being 1):

const NUMBERS: [i8; 2] = [0, 1];

fn test() {
    let current = 5;

    let string = match current % 2 {
        NUMBERS[0] => "even", // This does not work
        NUMBERS[1] => "odd",  // This does not work
        _ => unreachable!(),
    };

    // let string = match current % 2 {
    //     0 => "even",
    //     1 => "odd",
    //     _ => unreachable!()
    // };
}
4 Answers

You can use Match guards.

let string = match current % 2 {
    even if even == numbers[0] => "even",
    odd if odd == numbers[1] => "odd",
    _ => unreachable!()
};

Despite what the other answers say, it is possible to do what you want, but you need to make an explicitly named constant for each case.

const numbers: [i8; 2] = [
    0, 1
];

fn test() {
    let current = 5;
    
    const NUMBERS0: i8 = numbers[0];
    const NUMBERS1: i8 = numbers[1];

    let string = match current % 2 {
        NUMBERS0 => "even",   // This does not work
        NUMBERS1 => "odd",    // This does not work
        _ => unreachable!()
    };

    // let string = match current % 2 {
    //     0 => "even",
    //     1 => "odd",
    //     _ => unreachable!()
    // };
}

This works only because your expressions are const. Non-const expressions cannot be used in patterns. The intermediary NUMBERS0 and NUMBERS1 constants are necessary for syntax reasons. The left side of => is not an expression but a pattern. Some patterns look like expressions, but not all expressions have a pattern lookalike.

is it possible in rust to match on a dynamic variable

No. As the name implies, pattern-matching works on the basis of patterns, not expressions or values.

You can see this from the grammar: a MatchArm is OuterAttribute* Pattern MatchArmGuard?, and a pattern is an enumerated set of specific constructs. Mostly literals, identifiers, paths, and ways to combine those (structs, tuples, slice, ... patterns).

First calculate the value then pass to match

const numbers: [i8; 2] = [0, 1];
let current = 5;

let string = match numbers[current % 2] {
    0 => "even",
    1 => "odd",   
    _ => unreachable!()
};
println!("{}",string);
Related