0

I made a rust macro, that literally pastes some code to where i call it. I hardcoded some things into there, which it can't find unfortunaly.

That's how my code is structured:

macro_rules! foo {
    println!("{}", number);
}

fn bar() {
    let number: i32 = 10;
    foo!(); //--> cannot find 'number', even if it is right above here
}
v22
  • 5
  • 1

2 Answers2

3

You need to move the macro-definition into the scope of number, so number gets captured during the macro-definition and is available in the subsequent expansion:

fn main() {
    let number: i32 = 10;
    
    macro_rules! foo {
        () => { println!("{}", number); }
    }
    
    foo!();
}
user2722968
  • 13,636
  • 2
  • 46
  • 67
2

This is because of macro hygiene. Local identifiers introduced inside a macro cannot be used outside and vice versa.

The reason for this design choice is so that macros can't accidentally change the behaviour of unrelated code. You don't need to study the implementation of a macro to know for sure that it isn't going to have a naming collision with your own code.

It's a bit like how local variables inside a function are not visible to calling functions. Changing the name of a local variable in a function cannot break or change the meaning of code that happens to call that function.

There are two main ways to do what you want:

  1. Pass the identifier as an argument to the macro. This way, the identifier token originates outside of the macro, so it is allowed to refer to identifiers in that scope:
    macro_rules! foo {
        ($ident: ident) => {
             println!("{}", $ident);
        }
    }
    
    fn bar() {
        let number: i32 = 10;
        foo!(number);
    }
    
  2. The other way is to define the macro so that the variable is already in scope for the macro definition to use. See user2722968's answer. The downside of this solution is that you are very limited about where you can call it.
Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • Thanks! My goal with my macro was to minimize a funcrion call, which takes in some variables that always have the same name. So if i'd pass them into the macro, i could also call the function directly, which im going to do i think. – v22 Apr 27 '23 at 04:32