如何模拟varargs的实用功能?

时间:2018-04-10 17:15:03

标签: rust

Result.expect()的控制台输出不是我需要的,所以我使用自己的版本扩展了Result

trait ResultExt<T> {
    fn or_exit(self, message: &str) -> T;
}

impl<T> ResultExt<T> for ::std::result::Result<T, Error> {
    fn or_exit(self, message: &str) -> T {
        if self.is_err() {
            io::stderr().write(format!("FATAL: {} ({})\n", message, self.err().unwrap()).as_bytes()).unwrap();
            process::exit(1);
        }
        return self.unwrap();
    }
}

据我所知,Rust还没有支持varargs,所以我必须这样使用它,对吗?

something().or_exit(&format!("Ah-ha! An error! {}", "blah"));

与Java,Kotlin或C相比,它过于冗长。解决这个问题的首选方法是什么?

1 个答案:

答案 0 :(得分:3)

我不认为您建议的API特别符合人体工程学。如果最大性能很重要,将错误生成放在闭包中或为此提供API可能是有意义的,因此String仅在实际存在错误时分配,这可能在某些事情发生时尤为重要。格式特别昂贵。 (与std::result::Result的所有_else方法一样。)

但是,您可以通过定义一个获取结果的宏,&str和格式参数,使其更符合人体工程学。例如,这可能是这样的:(这是基于@ E_net4的评论)

macro_rules! or_exit {
    ($res:expr, $fmt:expr, $($arg:tt)+) => {
        $res.unwrap_or_else(|e| {
            let message = format!($fmt, $($arg)+);
            eprintln!("FATAL: {} ({})\n", message, e);
            process::exit(1)
        })
    };
}

fn main() {
    let x: Result<i32, &'static str> = Err("dumb user, please replace");
    let _ = or_exit!(x, "Ah-ha! An error! {}", "blahh");
}

Rust Playground

请注意,如果用户提供无效参数,这可能不会产生最佳错误消息,我不想过多地更改您的代码,但是如果您决定实际上只使用宏而没有其他任何内容,那么您应该扩展您的API取一个闭包而不是一个字符串。您可能还需要重新考虑宏的命名。