I tried to create a macro that replaces,
first: Some(first.as_ref().parse::<u64>().expect("'first' should be an unsigned integer"))
I've seen this done in other modules like Clap with values_t!
, my attempt to abstract this doesn't extend to types. I wrote this,
macro_rules! parse_u64 {
($var:ident) => {
Some(
$var
.as_ref()
.parse::<u64>()
.expect( format!("'{:?}' should be an unsigned integer", stringify!($var)) )
)
};
}
This produces the following error,
first: parse_u64!(first),
^^^^^^^^^^^^^^^^^ expected `&str`, found struct `String`
What am I doing wrong here: this is a simple macro with only three things in the chain? Why do I get this error and how can I fix it?
You can see this in this Rust Playground example
As you mentioned in your own answer, expect
takes a &str
so you can't pass in a String
directly:
.expect(format!("'{:?}' should be an unsigned integer", stringify!($var)).as_str())
However, this will perform string formatting (and allocate a new string) even if there was no error, so instead I would propose this:
.unwrap_or_else(|err| panic!("'{:?}' should be an unsigned integer: {}", stringify!($var), err))
This is effectively the same as the above, expect that unwrap_or_else
only invokes its closure in the error case.
Alternatively, in this specific case you can concatenate string literals at compile-time with concat!
, which also avoids the cost of format!
:
.expect(concat!("'", stringify!($var), "' should be an unsigned integer"))