ideasman42
ideasman42

Reputation: 48178

How to pass a blank / empty argument to a macro in Rust?

In some cases you may want to pass in an argument to a macro which is either some text, or nothing (blank space, as if nothing was written).

Given this starting point:

macro_rules! testme {
    ($var:ident, $code:block) => {
        for i in 0..10 {
            let $var = i;
            { $code }
            if $var > 5 {
                println!("over 5");
            }
        }
    }
}

fn main() {
    testme!(myvar, {
        println!("{}", myvar);
    });

}

We may want var to optionally be mutable, assuming the macro body is larger then in the example above, its best not to duplicate the entire macro.

macro_rules! testme {
    (private $var:ident, $code:block, $var_qual:tt) => {
        for i in 0..10 {
            // imagine this is a lot more code :)
            let $var_qual $var = i;
            { $code }
            if $var > 5 {
                println!("over 5");
            }
        }
    };
    (mut $var:ident, $code:block) => {
        testme!(private $var, $code, mut)
    };
/*
    ($var:ident, $code:block) => {
        testme!(private $var, $code, )
        //                          ^ how to pass in a blank argument?
    };
*/
}

fn main() {
    testme!(mut myvar_mut, {
        myvar_mut += 10;
        println!("{}", myvar_mut);
    });
/*
    testme!(myvar_immutable, {
        println!("{}", myvar_immutable);
    });
*/
}

As far as I can tell there is no way to pass in a an empty argument, uncomment the /**/ comments to see the error.


Is it possible to pass in an empty argument to a macro to make an example like this work?

Upvotes: 5

Views: 2750

Answers (1)

ideasman42
ideasman42

Reputation: 48178

As far as I know its not possible to pass in blank / empty arguments.

It is possible however to pass in a locally defined macro which optionally adds a prefix.

Working example:

macro_rules! testme {
    (private $var:ident, $code:block, $var_qual_macro:ident) => {
        for i in 0..10 {
            // imagine this is a lot more code :)
            let $var_qual_macro!($var) = i;
            { $code }
            if $var > 5 {
                println!("over 5");
            }
        }
    };
    (mut $var:ident, $code:block) => {
        macro_rules! var_qualifier { ($v:ident) => { mut $v } }
        testme!(private $var, $code, var_qualifier)
    };
    ($var:ident, $code:block) => {
        macro_rules! var_qualifier { ($v:ident) => { $v } }
        testme!(private $var, $code, var_qualifier)
    };
}

fn main() {
    testme!(mut myvar_mut, {
        myvar_mut += 10;
        println!("{}", myvar_mut);
    });
    testme!(myvar_immutable, {
        println!("{}", myvar_immutable);
    });
}

Take care when nesting macros like this that the name of the macro (var_qualifier in this case) is isn't the same name used inside a different macro since the name will be silently shadowed.

Upvotes: 4

Related Questions