Search code examples
rustmacrosreturnrust-macros

Rustlang: Adding a return statement in a macro


I'm going through the rustlings course in order to learn rustlang and I'm working on quiz 4. The following is the solution I found.

macro_rules! my_macro {
    ($val:expr) => {
       format!("Hello {}", $val)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_my_macro_world() {
        assert_eq!(my_macro!("world!"), "Hello world!");
    }

    #[test]
    fn test_my_macro_goodbye() {
        assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
    }
}

But before this, I unsuccessfully tried the following:

macro_rules! my_macro {
    ($val:expr) => {
       return format!("Hello {}", $val)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_my_macro_world() {
        assert_eq!(my_macro!("world!"), "Hello world!");
    }

    #[test]
    fn test_my_macro_goodbye() {
        assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
    }
}

The only difference in this non-working solution being the return keyword. In this case, the compiler spits out a whole list of errors and warnings.

Why is this not correct? Are return statements not allowed from within a rust macro?


Solution

  • When you call a macro, its body is pasted* into the place where it's called.

    This means that in the second snippet, this:

    #[test]
    fn test_my_macro_world() {
        assert_eq!(my_macro!("world!"), "Hello world!");
    }
    

    is expanded to this:

    #[test]
    fn test_my_macro_world() {
        assert_eq!(return format!("Hello {}", "world!"), "Hello world!");
    }
    

    which causes a type error.


    * It's a bit more complicated than that: there's some magic that prevents naming collisions as well.