Same macro expansion and different result

I do not understand why Program One is failing ?

While trying to understand what is going on, I tired Program Two,
which does not fail.

If I run cargo expand with Program One or Program Two as main.rs,
I get the same standard output (standard error is different).

I also do not understand why two programs can have the same macro expansion,
and one fail while the other does not ?

Program One:

macro_rules! set_value {
    (one) => {
        let value = 1.0;
    };
    (two) => {
        let value = 2.0;
    };
}
fn main() {
    set_value!(one);
    println!( "{}", value);
}

Result One:

  --> src/main.rs:11:21
   |
11 |     println!( "{}", value);
   |                     ^^^^^ not found in this scope

Program Two:

macro_rules! set_value {
    (one) => {
        let value = 1.0;
        println!( "{}", value);
    };
    (two) => {
        let value = 2.0;
        println!( "{}", value);
    };
}
fn main() {
    set_value!(one);
}  

Result Two:

1

cargo expand loses some of the context of macros.
Macros in Rust are hygienic, that means identifiers created inside your macro are not visible at the call site.

So for your first example the let value inside that macro is not visible after you call set_value.
See this larger example to demonstrate it a bit more:

macro_rules! set_value {
    (one) => {
        let value = 1.0;
    };
}
fn main() {
    let value = 3;
    set_value!(one);
    println!( "{}", value);
}

The value inside your macro is an entirely different identifier than the one in main. It just happens to have the same name.

If you want your macro to create an identifier that's visible afterwards you need to pass it in, for example:

macro_rules! set_value {
    ($v:ident, one) => {
        let $v = 1.0;
    };
}
fn main() {
    set_value!(value, one);
    println!( "{}", value);
}

Or you have to return a value so it can be assigned:

macro_rules! set_value {
    (one) => {{
        let value = 1.0;
        value
    }};
}
fn main() {
    let value = set_value!(one);
    println!( "{}", value);
}
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.