How to write a panic! like macro in Rust?

2019-03-06 16:54发布

问题:

For fatal error handling, I'm using the panic! macro, but I would prefer to have a macro that did not print the file/line information, only the error message.

I read the macro documentation, but my understanding is a bit shaky.

I looked at the source of the panic! macro, but it's calling functions to do its work where the file and line information is an integral part of the operation, so I can't just tweak that.

I looked at the println! macro, which looks more promising, but I have two problems I an unaware of how to solve.

macro_rules! die {
    () => (print!("\n"));
    ($fmt:expr) => (print!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*); exit(-1));
}

If I put the exit() call in, as I have on the last line, I get syntax errors when trying to call it.

If I remove the exit(), I don't get complaints about the macro, but this code fails to compile:

let file = match File::open(&path) {
    Err(why) => die!("Couldn't open {}: {}", display, why.description()),
    Ok(file) => file,
};

Whereas it does compile when die! is replaced with panic!. I assume there is some magic about panic! which tells the compiler that it never returns?

回答1:

First, if I put the exit() call in, as I have on the last line, I get syntax errors when trying to call it.

That is because a macro should expand to a single item, and here it expands to two. You can simply wrap the invocation in a block {} and it'll just work... once you qualify the call to exit.

({ print!(concat!($fmt, "\n"), $($arg)*); std::process::exit(-1) });

If I remove the exit(), I don't get complaints about the macro, but this code fails to compile. Whereas it does compile when die is replaced with panic. I assume there is some magic about panic which tells the compiler that it never returns?

It's not so much magic as the ! type. The panic and exit functions both return ! which is a type with no value: it cannot ever be constructed.

This is sufficient for the compiler to know that those functions will never return (they diverge), so from the point of view of type-checking, ! is considered a subtype of all types and does not cause issues.



标签: rust