0
votes

I've been enjoying navigating Rust through its type system. But when it goes into macros I find it difficult to follow. In the below example, why is it ok to pass "target_name" to target but not assign it then pass the assignment in? How do you navigate the macro in tracing such that the below is obvious to you? I am asking this as much from a developer experience perspective as a programmer. (I'm definitely looking for a "teach a man to fish" style answer.)

info!(target: "target_name", "message"); // fine, must be cast to &str?
let target_name = "target_name"; // must be cast to String?
info!(target: target_name, "message"); // not fine

The latter call results in:

error[E0435]: attempt to use a non-constant value in a constant
   |
44 |         info!(target: target_name, "message");
   |                       ^^^^^^^^^^^ non-constant value

Even if I switch to &target_name.as_str() which I believe should be constant (not growable like String) the macro still fails with the same error. This is where my mental map is failing. I can understand that the assumed type when assigning is wrong, but then when I recast it, why would it fail?

1
Does it need a static lifetime? Have you tried with const target_name : &str = "..."? - tadman
Yes that works! So it's not just that the macro is coercing to &str but also that it is somehow making it const? Where in the macro can I read to understand this? - Alex Moore-Niemi

1 Answers

0
votes

The solution here is to use a const with a type that's compatible with expectations, like:

const target_name : &str = "target_name";

You can usually view the source for these macros in the documentation, as shown here:

#[macro_export(local_inner_macros)]
macro_rules! info {
    (target: $target:expr, $($arg:tt)+) => (
        log!(target: $target, $crate::Level::Info, $($arg)+)
    );
    ($($arg:tt)+) => (
        log!($crate::Level::Info, $($arg)+)
    )
}

That's just a wrapper around log!, so it's not especially informative, and log! is just a wrapper around __private_api_log which is even less helpful.