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

Vit*_*meo 8 rust

我发现自己.expect("...")在许多我不关心从错误中恢复的地方使用了一个有用的错误信息.例:

let p = "foo.txt";
let f = File::open(p).expect("File not found");
Run Code Online (Sandbox Code Playgroud)

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

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

这有两个问题:

  1. format通话将被急切地评估.

  2. 这是不必要的冗长.

理想情况下,我想写:

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

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

我发现的唯一选择是:

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

对我来说,这仍然有点过于冗长.

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

She*_*ter 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));
}
Run Code Online (Sandbox Code Playgroud)

您可以根据需要随意调整特征边界.

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

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


att*_*ona 5

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

macro_rules! crash {
    ( $( $p:tt ),* ) => {
        |_| panic!($($p),*);
    };
}
Run Code Online (Sandbox Code Playgroud)

然后声明糖化为:

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

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

您是否将错误链故障视为错误管理设计的替代方案?

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

使用一个简单的宏,你应该创造性地调整语法以接近你的渴望,在一个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(())
}
Run Code Online (Sandbox Code Playgroud)

读作:调用chain_error具有可变参数arg列表的方法.