1

I'm trying to complete Quiz #4 in the Rustlings exercises:

// Write a macro that passes the quiz! No hints this time, you can do it!

#[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!");
    }
}

my macro looks like this:

#[macro_export]
macro_rules! my_macro {
    (($val:expr), "world!") => {
        println!("Hello world!");
    };
    (($val:expr), "goodbye!") => {
        println!("Hello goodbye!");
    };
}

This was patterned after the Declarative Macro section of the Rust Language Documentation. I get the following errors:

assert_eq!(my_macro!("world!"), "Hello world!");
   |                              ^^^^^^^^^^ no rules expected this token in macro call

assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
   |                              ^^^^^^^^^^ no rules expected this token in macro call

I cannot find a solution to this to make it compile. Help!

chasahodge
  • 373
  • 1
  • 4
  • 11

4 Answers4

5

I think the idea of the exercise is to find a way that by using the macro we get the string "Hello whatever". I'm a newbie at Rust too, but I've been able to do the exercise this way:

#[macro_use]
macro_rules! my_macro {
    ($val:expr) => {
        format!("Hello {}",$val);
    }
}

I'm waiting for feedback!

Max
  • 76
  • 6
1

You shouldn't use format!() in a macro like in @Max's answer, you should use concat! instead, because it produces a string slice at compile time instead of formatting at runtime:

macro_rules! my_macro {
    ($val:tt) => {
        concat!("Hello ", $val);
    }
}
Deadbeef
  • 1,499
  • 8
  • 20
0

After clearing my head and thoroughly examining the error messages I figured it out. Here's the solution:

#[macro_export]
macro_rules! my_macro {
    ($("world!"),*) => {
        "Hello world!"
    };
    ($("goodbye!"),*) => {
        "Hello goodbye!"
    };
}

#[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!");
    }
}

I was making it too complicated.

chasahodge
  • 373
  • 1
  • 4
  • 11
  • 1
    This way it works, but is a little too complicated, too. Hints: 1) What does the `$(something),*` construction do in your case? 2) What is the difference between branches? 3) Do you know about https://doc.rust-lang.org/stable/std/macro.concat.html? – Cerberus Jul 05 '20 at 05:09
0

The question in Quiz4 also requires the use of modules. This works perfectly for me. I also think format! works too but I chose to use conact!.

#[macro_use]
mod macros {
   macro_rules! my_macro {
     ($val: expr) => {
         concat!("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!");
  }
}
Ian Githungo
  • 1
  • 1
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 16 '21 at 15:02