4

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?

geofflittle
  • 437
  • 1
  • 3
  • 14

1 Answers1

5

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.

Lambda Fairy
  • 13,814
  • 7
  • 42
  • 68