Implementing a switch-like statement with macros

⚓ Rust    📅 2025-10-24    👤 surdeus    👁️ 3      

surdeus

hi there,

I am still learning Rust and as a self-assigned exercize to better understand macros, I am trying to implement a switch-like statement with macros.

Basically, I'd like to replicate the switch from Go, and translate this:

fn foo(cut: f64) {
    let v = 42.0;
    switch! {
        v > cut      => println!("passing cut"),
        v < -cut     => println!("case 2"),
        v == cut/2.0 => println!("special case 3"),
        v == 42.0    => println!("answer to the universe"),
        _            => println!("default case"),
    }
}

to a chain of if-else-ifs:

fn foo(cut: f64) {
    let v = 42.0;
    if v > cut {
        println!("passing cut");
    } else if v < -cut {
        println!("case 2");
    } else if v == cut / 2.0 {
        println!("special case 3");
    } else if v == 42.0 {
        println!("answer to the universe");
    } else {
        println!("default case");
    }
}

as a first stab, I tried this:

macro_rules! switch {
    ($($a:expr => $b:expr $(,)?)*) => {
        $(if $a {
            return $b;
        })*
    };
    (_ => $e:expr $(,)?) => {
        $(if true {
            return $e;
        })*
    };
}

but of course that doesn't work (I guess I am not using the correct pattern matcher to match for _):

error: in expressions, `_` can only be used on the left-hand side of an assignment
  --> main.rs:88:9
   |
88 |         _ => println!("default case"),
   |         ^ `_` not allowed here

I then tried:

macro_rules! switch {
    ($($a:expr => $b:expr,)* _ => $e:expr $(,)?) => {
        $(if $a {
            return $b;
        })*
        if true {
            return $e;
        }
    };
}

and got:

error: local ambiguity when calling macro `switch`: multiple parsing options: built-in NTs expr ('a') or 1 other option.
  --> main.rs:88:9
   |
88 |         _ => println!("default case"),
   |         ^

→ I guess macro_rules doesn't cut it for what I'd like to achieve and I would need to resort to TokenStreams ?
(we need to keep some state to remember whether we are considering the first switch-case, the last/default one or any other case. And it seems to macro_rules doesn't provide this kind of information).

→ but perhaps the more fundamental question is: can this (a switch-like statement) be achieved at all ?

thanks for your time and input.
-s

4 posts - 4 participants

Read full topic

🏷️ Rust_feed