Rustlings Topic: Macro

Rust’s macro system is very powerful, but also kind of difficult to wrap your head around. We’re not going to teach you how to write your own fully-featured macros. Instead, we’ll show you how to use and create them.

You may find solution code for the topic from my repo.

  1. macros1.rs
  2. macros2.rs
  3. macros3.rs
  4. macros4.rs

macros1.rs

Writing macro for Rust is another level of difficulty. But many libraries provide very useful macros. So it is important to know (at least) how to use them.

To define a macro, we use the macro_rules! construct. To invoke the macro, we append ! after the macro name.

/* file: "exercises/macros/macros1.rs" */
macro_rules! my_macro {
    () => {
        println!("Check out my macro!");
    };
}

fn main() {
    my_macro!();
}

macros2.rs

Macros don’t quite play by the same rules as the rest of Rust, in terms of what’s available where. Unlike other things in Rust, the order of “where you define a macro” versus “where you use it” actually matters.

error: cannot find macro `my_macro` in this scope
 --> exercises/macros/macros2.rs:4:5
  |
4 |     my_macro!();
  |     ^^^^^^^^
  |
  = help: have you added the `#[macro_use]` on the module/import?

warning: unused macro definition: `my_macro`
 --> exercises/macros/macros2.rs:7:14
  |
7 | macro_rules! my_macro {
  |              ^^^^^^^^
  |
  = note: `#[warn(unused_macros)]` on by default

error: aborting due to previous error; 1 warning emitted

If we run the code without any modification, we see one error and one warning. First, we get the error for can’t find macro my_macro, and yet we get another warning for unused macro definition: my_macro!

It turns out the order of macro definition and usage is important. We have to place definitions before we use them.

/* file: "exercises/macros/macros2.rs" */
macro_rules! my_macro {
    () => {
        println!("Check out my macro!");
    };
}

fn main() {
    my_macro!();
}

macros3.rs

We have the my_macro definition within mod macros. Thus when we use my_macro outside of the mod(main), the Rust compiler cannot find it.

error: cannot find macro `my_macro` in this scope
  --> exercises/macros/macros3.rs:22:5
   |
22 |     my_macro!();
   |     ^^^^^^^^
   |
   = help: have you added the `#[macro_use]` on the module/import?

Rust compiler gives you a hint to use #[macro_use] on the module/import. Take a look at the documentation about macro_use. We can also append #[macro_export] to the macro definition to use it outside of the module.

/* file: "exercises/macros/macros3.rs" */
// https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute
// #[macro_use] attribute can be used to make a module's macro
// scope not end when the module is closed.
#[macro_use]
mod macros {
    // Macros labeled with #[macro_export] are always pub and
    // can be referred to by other crates, either by path or
    // by #[macro_use] as described above.
    // #[macro_export]
    macro_rules! my_macro {
        () => {
            println!("Check out my macro!");
        };
    }
}

fn main() {
    my_macro!();
}

macros4.rs

Append ; between macro arms. I’m not sure why this exercise exists…

/* file: "exercises/macros/macros4.rs" */
macro_rules! my_macro {
    () => {
        println!("Check out my macro!");
    };
    ($val:expr) => {
        println!("Look at this other macro: {}", $val);
    };
}

fn main() {
    my_macro!();
    my_macro!(7777);
}

Continue with Rustlings Solution