Search code examples
typesrustrust-macros

Rustlings Course Test4.rs Marcro Return Type Issue


I am doing the Rustlings Rust-lang course and working on exercises/test4.rs

This is the only exercise in the course that does not come with a hint. So after working on it for a while, I'm reaching out to get that hint here!

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

fn main() {
    if my_macro!("world!") != "Hello world!" {
        panic!("Oh no! Wrong output!");
    }
}

When I try to compile, I get the following error:

error[E0308]: mismatched types
  --> test4.rs:20:31
   |
20 |     if my_macro!("world!") != "Hello world!" {
   |                               ^^^^^^^^^^^^^^ expected (), found reference
   |
   = note: expected type `()`
              found type `&'static str`

error: aborting due to previous error

The issue seems to be based on the fact that the default return type for a Rust macro is an empty tuple type (ie expected type ()), where as we compare it to a static string.

If the parameters of the exercise would allow me to alter the code in the main function, then the exercise seems like it would be a bit simpler. However, according to the instruction, the only thing to be done is to write a macro that causes the code to compile.

As I understand it, you cannot explicitly declare a return type for a macro. So I am at a loss as to how to proceed.


Solution

  • So here is the working answer I came up with:

    fn function_rules(expr:&str)-> String{
        let a = "Hello";
        let b = expr;
        let result = [a, b].join(" ");
        return result.to_string();
    }
    
    macro_rules! my_macro {
        () => {
            println!("Hello!");
        };
        ($val:expr) => {
            //println!("Hello {}", $val);
            function_rules($val)
        }
    }
    
    fn main() {
        if my_macro!("world!") != "Hello world!" {
            panic!("Oh no! Wrong output!");
        }
    }
    

    I big part of solving this problem was dealing with String vs &str types, an excellent coverage of which can be found here.

    The code compiles without modifying the main() function in any way, as per the instruction perameters. I think an even more elegant solution would have been to write a macro that returned the correct type without relying on an extra function. Assuming that's possible!