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?
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.