我正在铁 rust 的一个大项目上工作,有很多移动的碎片.我的议程之一是在任何部分出现错误时记录错误,以便稍后进行调试. 然而,似乎每个函数调用的简洁性都消失了,这似乎是因为我的天真.

我怎样才能让它更简洁呢?我看了看这个question,它本质上要求使用match来同时捕获OK()Err.

fn pathway_1(x: &str, y: &str) -> Option<Vec<String>> {
    let unique_numbers = match query_unique_numbers(&x,  &y) {
        Ok(r) => r
        Err(e) => {
        log::error!(target: "normal", "Could not query unique numbers. Err {e}");
        return None;
        }
    }

    let unique_people = match query_unique_people(&unique_numbers,  &y) {
        Ok(r) => r
        Err(e) => {
        log::error!(target: "normal", "Could not query unique people. Err {e}");
        return None;
        }
    }

    let relevant_things_by_people = match query_relevant_things(&unique_people,  &y) {
        Ok(r) => r
        Err(e) => {
        log::error!(target: "normal", "Could not query relevant things. Err {e}");
        return None;
        }
    }

    /// Many such function calls below.

    Some(vector_of_strings)
}

推荐答案

您可以使用.ok()Result转换为Option,然后使用?传播它.

可以使用.map_err()来记录每个结果,以便对错误应用"转换".使用.inspect_err()(稳定后)或.tap_err()(来自tap箱)可能会稍好一些,但由于在记录后不会使用错误,因此这并不重要:

fn pathway_1(x: &str, y: &str) -> Option<Vec<String>> {
    let unique_numbers = query_unique_numbers(&x, &y)
        .map_err(|e| { log::error!(target: "normal", "Could not query unique numbers. Err {e}"); })
        .ok()?;

    let unique_people = query_unique_people(&unique_numbers, &y)
        .map_err(|e| { log::error!(target: "normal", "Could not query unique people. Err {e}"); })
        .ok()?;

    let relevant_things_by_people = query_relevant_things(&unique_people, &y)
        .map_err(|e| { log::error!(target: "normal", "Could not query relevant things. Err {e}"); })
        .ok()?;

    /// Many such function calls below.

    Some(vector_of_strings)
}

然而,我不会这样做的.您似乎在返回类型中使用了Option来表示失败.如果是这样的话,您应该返回Result.如果这样做,您可以创建一个适当的包含错误类型,它可以表示哪个步骤失败了,原始错误是什么,以及显示逻辑(使用类似thiserror箱的内容):

use thiserror::Error;

#[derive(Error, Debug)]
enum QueryError {
    #[error("Could not query unique numbers. Err {0}")]
    UniqueNumbers(SomeError),
    #[error("Could not query unique people. Err {0}")]
    UniquePeople(SomeError),
    #[error("Could not query relevant things. Err {0}")]
    RelevantThings(SomeError),
}

fn pathway_1(x: &str, y: &str) -> Result<Vec<String>, QueryError> {
    let unique_numbers = query_unique_numbers(&x, &y)
        .map_err(QueryError::UniqueNumbers)?;

    let unique_people = query_unique_people(&unique_numbers, &y)
        .map_err(QueryError::UniquePeople)?;

    let relevant_things_by_people = query_relevant_things(&unique_people, &y)
        .map_err(QueryError::RelevantThings)?;

    /// Many such function calls below.

    Ok(vector_of_strings)
}

然后,您可以在调用方的一个位置处理所有错误.例如:

match pathway_1(x, y) {
    Ok(vector_of_strings) => {
        // do something
    }
    Err(e) => {
        log::error!(target: "normal", "{e}");
    }
}

Rust相关问答推荐

移植带有可变borrow 的C代码-卸载期间错误(nappgui示例)

什么是谓词的简短和简洁类型

为什么拥有的trait对象的相等运算符移动了正确的操作数?

trait声明中的生命周期参数

在泛型 struct 的字段声明中访问关联的Conant

有没有更好的方法从HashMap的条目初始化 struct ?

获取字符串切片(&;str)上的切片([ia..ib])返回字符串

类型批注需要静态生存期

如果包名称与bin名称相同,并且main.ars位于工作区的同一 crate 中,则无法添加对lib.ars的依赖

如果死 struct 实现了/派生了一些特征,为什么Rust会停止检测它们?

如何创建一个可变的嵌套迭代器?

如何在 Rust 中将函数项变成函数指针

Rust 并行获取对 ndarray 的每个元素的可变引用

返回迭代器考虑静态生命周期类型

为什么 Rust 字符串没有短字符串优化 (SSO)?

如何为已实现其他相关 std trait 的每个类型实现一个 std Trait

rust 中不同类型的工厂函数

If let expression within .iter().any

Rust,我如何正确释放堆分配的内存?

为什么一个整型变量赋值给另一个变量后仍然可以使用?