无论如何,“context”和“with_context”之间有什么区别?

Pau*_*erg 3 methods error-handling closures lazy-evaluation rust

这是无论如何Context的文档:

/// Wrap the error value with additional context.
fn context<C>(self, context: C) -> Result<T, Error>
where
    C: Display + Send + Sync + 'static; 
Run Code Online (Sandbox Code Playgroud)
/// Wrap the error value with additional context that is evaluated lazily
/// only once an error does occur.
fn with_context<C, F>(self, f: F) -> Result<T, Error>
where
    C: Display + Send + Sync + 'static,
    F: FnOnce() -> C;
Run Code Online (Sandbox Code Playgroud)

在实践中,不同之处在于with_context需要一个闭包,如无论如何的README所示:

use anyhow::{Context, Result};

fn main() -> Result<()> {
    // ...
    it.detach().context("Failed to detach the important thing")?;

    let content = std::fs::read(path)
        .with_context(|| format!("Failed to read instrs from {}", path))?;
    // ...
}
Run Code Online (Sandbox Code Playgroud)

但看起来我可以用 替换with_context方法context,通过删除来摆脱闭包||,并且程序的行为不会改变。

引擎盖下的两种方法有什么区别?

kfe*_*v91 8

关闭提供给 with_context是惰性求值的,您使用with_contextovercontext的原因与您选择惰性求值任何事物的原因相同:它很少发生并且计算成本很高。一旦满足这些条件,就with_context变得比 更可取context。评论伪示例:

fn calculate_expensive_context() -> Result<()> {
    // really expensive
    std::thread::sleep(std::time::Duration::from_secs(1));
    todo!()
}

// eagerly evaluated expensive context
// this function ALWAYS takes 1+ seconds to execute
// consistently terrible performance
fn failable_operation_eager_context(some_struct: Struct) -> Result<()> {
    some_struct
        .some_failable_action()
        .context(calculate_expensive_context())
}

// lazily evaluated expensive context
// function returns instantly, only takes 1+ seconds on failure
// great performance for average case, only terrible performance on error cases
fn failable_operation_lazy_context(some_struct: Struct) -> Result<()> {
    some_struct
        .some_failable_action()
        .with_context(|| calculate_expensive_context())
}
Run Code Online (Sandbox Code Playgroud)


Jas*_*son 7

正如无论如何::Context::with_context的文档所述:

用附加上下文包装错误值,仅在发生错误时才延迟评估。

如果传递给的内容context可能在计算上很昂贵,那么最好使用with_context,因为传递的闭包仅在with_context调用时才进行评估。这被称为以惰性而非急切的方式进行评估。

标准库中也存在类似的行为,例如: