是否可以实现采用格式字符串的方法?

时间:2017-07-05 09:42:26

标签: rust

我发现自己使用.expect("...")在许多我不关心从错误中恢复的地方发出有用的错误消息。例如:

let p = "foo.txt";
let f = File::open(p).expect("File not found");

但是,我想使用格式化的字符串打印更多信息。这就是我能做的:

let f = File::open(p).expect(&format("{} not found", p));

这有两个问题:

  1. 将热切评估format来电。

  2. 这是不必要的冗长。

  3. 理想情况下,我想写一下:

    // pseudocode
    let f = File::open(p).expect_fmt("{} not found", p);
    

    但是我认为没有可变参数泛型函数和字符串的编译时解析是不可能的。

    我发现的唯一选择是:

    let f = File::open(p).unwrap_or_else(|_| panic!("{} not found", p));
    

    根据我的口味,这仍然有点过于冗长。

    如果答案每晚使用Rust,那是可以接受的。

2 个答案:

答案 0 :(得分:7)

TL; DR:否。

虽然在减少冗长问题方面没有太多工作要做,但您可以使用std::fmt::Arguments

来避免内存分配
trait ResultExt<T, E> {
    fn expect_fmt<D>(self, msg: D) -> T
    where
        D: std::fmt::Display;
}

impl<T, E> ResultExt<T, E> for Result<T, E>
where
    E: std::error::Error,
{
    fn expect_fmt<D>(self, msg: D) -> T
    where
        D: std::fmt::Display,
    {
        match self {
            Ok(t) => t,
            Err(e) => panic!("{}: {}", msg, e),
        }
    }
}

use std::fs::File;

fn main() {
    let p = "foo.txt";
    let f = File::open(p).expect_fmt(format_args!("{} not found", p));
}

随意调整特质边界。

  如果没有可变参数泛型函数和编译时解析字符串

是不可能的

这正是format_args宏所做的,但你仍然需要调用它。

答案 1 :(得分:5)

为了避免急切地格式化错误消息,可以使用一个闭包,一个简单的宏来减少冗长:

macro_rules! crash {
    ( $( $p:tt ),* ) => {
        |_| panic!($($p),*);
    };
}

然后该声明糖化为:

    let f = File::open(p).unwrap_or_else(crash!("{} not found", p));

这种方法没有太大的附加价值。

您是否考虑过error-chainfailure作为错误管理设计的替代方案?

他们可以为有效的错误处理提供很多帮助。

使用简单的宏,无论如何都应该创造性地调整 语法以接近您的需求,低于基于error-chain的示例:

macro_rules! or {
    ( $( $p:tt ),* ) => {{
        || format!($($p),*)
    }};
}

fn run() -> Result<()> {
    use std::fs::File;
    // This operation will fail
    let p = "foo";

    File::open(p).chain_err(or!("unable to open {} file", p))?;

    Ok(())
}

读作:使用可变参数arg列表调用chain_error方法。