rust从0开始写项目-04-多样化错误处理

一个优秀的项目,错误处理的优雅性是至关重要的,而rust,anyhow creat是绕不过去的一个,今天我们来研究下,怎么使用它,帮助我们写出更优雅的代码

关注 vx golang技术实验室,获取更多golang、rust好文

Part1一、anyhow

anyhow::Error 是这个 crate 中最重要的结构体,它是动态错误类型的包装器,能从所有实现了 std::error::Error + Send + Sync + 'static 的错误转换而来,也能转换成 Box,它有以下特点:

  1. anyhow::Error 要求包裹的错误必须是 Send + Sync + 'static
  2. anyhow::Error 保证 backtrace 是可用的,就是底层的错误类型没有提供;
  3. anyhow::Error 在内存中只占一个机器字而不是两个;

11.1 打印anyhow方式

  1. 可以使用 {} 或者 .to_string(),但是仅仅打印最外层错误或者上下文,而不是内层的错误;

  2. 可以使用 {:#} 打印外层和底层错误;

  3. 可以使用 {:?} 在调试模式打印错误以及调用栈;

  4. 可以使用 {:#?} 以结构体样式打印错误,例如:

    Error {
    context: "Failed to read instrs from ./path/to/instrs.json",
    source: Os {
    code: 2,
    kind: NotFound,
    message: "No such file or directory",
    },
    }

21.2 downcast_ref

anyhow 提供了 downcast_ref 方法,用于在运行时将 anyhow::Error 转换为其包含的具体错误类型的引用。这可以用于检查和处理特定类型的错误。

复制代码
use anyhow::{anyhow,Error};
use thiserror::Error;

#[derive(Error, Debug)]
pub enum  MyError {
    #[error("the data for key `{0}` is not available")]
    Redaction(String)
}

pub fn anyhow_use(){
    let error: Error = anyhow!(MyError::Redaction("keys".to_string()));

    if let Some(my_error) = error.downcast_ref::<MyError>() {
        println!("MyError is parse ok: {}", my_error);
        // Handle MyError specifically
    } else {
        println!("Unknown error: {:?}", error);
        // Handle other types of errors
    }
}

MyError is parse ok: the data for key `keys` is not available

31.3 anyhow!

使用 anyhow! 这个宏可以生成 anyhow::Error类型的值,它可以接受字符串,格式化字符串作为参数,或者实现 std::error:Error 的错误作为参数。

复制代码
use anyhow::{anyhow,Error,Result};

fn anyhow()->Result<()>{

    return Err(anyhow!("this is return error"))
}
pub fn anyhow_use(){
    let err = anyhow();
    println!("{:#?}",err)
}

Err(
    "this is return error",
)

41.4 anyhow配合thiserror使用

项目更多用到的组合

复制代码
use anyhow::{anyhow, Error, Result};
use thiserror::Error;

#[derive(Error, Debug)]
pub enum DataStoreError {
    #[error("the data for key `{0}` is not available")]
    Redaction(String),
}

fn bar() -> std::result::Result<(), DataStoreError> {
    Err(DataStoreError::Redaction(
        "bar() std::result::Result".to_string(),
    ))
}

fn foo() -> anyhow::Result<()> {
    let a = bar()?;
    Ok(())
}

fn foo2() -> anyhow::Result<()> {
    Err(anyhow::Error::from(DataStoreError::Redaction(
        "foo2 (anyhow::Error::from(DataStoreError::Redaction ".to_string(),
    )))
}

fn foo3() -> anyhow::Result<()> {
    Err(anyhow!(DataStoreError::Redaction(
        "foo3 anyhow!(DataStoreError::Redaction".to_string()
    )))
}

fn foo4() -> anyhow::Result<()> {
    Err(anyhow!("foo4 anyhow! {}", "f4"))
}

pub fn anyhow_use() {
    // let err = anyhow();
    // println!("{:#?}",err)

    let f = foo();
    println!("foo {:?}", f);
    let f1 = foo2();
    println!("foo2 {:?}",f1);

    let f2 = foo3();
    println!("foo3 {:?}",f2);

    let f3 = foo4();
    println!("foo4 {:?}",f3);
}

foo Err(the data for key `bar() std::result::Result` is not available)
foo2 Err(the data for key `foo2 (anyhow::Error::from(DataStoreError::Redaction ` is not available)
foo3 Err(the data for key `foo3 anyhow!(DataStoreError::Redaction` is not available)
foo4 Err(foo4 anyhow! f4)

51.5 bail!

anyhow::bail 宏用于提前错误返回,它等价于 return Err(anyhow!($args...)),包含这个宏的函数的返回值必须是 Result<_,anyhow::Error>

复制代码
use anyhow::{anyhow,bail, Error, Result};
use futures::future::err;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum DataStoreError {
    #[error("the data for key `{0}` is not available")]
    Redaction(String),
}


fn bail(i:i16)->anyhow::Result<()>{

    if i < 16{
        bail!(DataStoreError::Redaction(i.to_string() + &" is less 16".to_string()))
    }
    Ok(())
}

直接返回

复制代码
bail! error Err(the data for key `1 is less 16` is not available)

61.6 anyhow::Context

anyhow::Contextanyhow::Result 类型提供了 context 方法,能在错误发生时提供更多的上下文信息:

复制代码
use anyhow::{anyhow, bail, Context, Error, Result};
use futures::future::err;
use std::fs;
use std::path::PathBuf;
use thiserror::Error;


pub struct ImportantThing {
    path: PathBuf,
}

impl ImportantThing {
    pub fn detach(&mut self) -> Result<()> {
        Err(anyhow!("detach failed"))
    }
}

pub fn do_it(mut it: &mut ImportantThing) -> Result<Vec<u8>> {
    it.detach()
        .context("Failed to detach the important thing")?;
    let path = &it.path;
    let context =
        fs::read(path).with_context(|| format!("Failed to read in str form {}", path.display()))?;
    Ok(context)
}

pub fn do_it1(it: &mut ImportantThing) -> Result<Vec<u8>> {
    let path = &it.path;
    let content =
        fs::read(path).with_context(|| format!("Failed to read instrs from {}", path.display()))?;

    Ok(content)
}
pub fn anyhow_use() {
    // let err = anyhow();
    // println!("{:#?}",err)

    // let f = foo();
    // println!("foo {:?}", f);
    // let f1 = foo2();
    // println!("foo2 {:?}",f1);
    //
    // let f2 = foo3();
    // println!("foo3 {:?}",f2);
    //
    // let f3 = foo4();
    // println!("foo4 {:?}",f3);

    // let b = bail(1);
    // println!("bail! error {:?}", b)

    let mut it = ImportantThing{
        path:PathBuf::new()
    };

    match do_it(&mut it) {
        Ok(_)=>(),
        Err(err)=>{
            for cause in err.chain(){
                println!("{}",cause)
            }
        }
    }

    match do_it1(&mut it) {
        Ok(_)=>(),
        Err(err)=>{
            for cause in err.chain(){
                println!("{}",cause)
            }
        }
    }

}

Failed to detach the important thing
detach failed

Failed to read instrs from 
No such file or directory (os error 2)

本文由mdnice多平台发布

相关推荐
一米阳光zw12 分钟前
Spring Boot中使用 MDC实现请求TraceId全链路透传
java·spring boot·后端·traceid·mdc
王元_SmallA26 分钟前
pgsql:connection failed connection to server at
java·后端
绝无仅有29 分钟前
大厂面试相关文章:深入技术面试中的核心知识点
后端·面试·架构
绝无仅有32 分钟前
面试文章:网络协议与redis安全,https协议,TCP三次握手,四次挥手等面试经典问题
后端·面试·架构
IT_陈寒1 小时前
7个鲜为人知的JavaScript性能优化技巧,让你的网页加载速度提升50%
前端·人工智能·后端
几颗流星1 小时前
Rust 常用语法速记 - 迭代器
后端·rust
清空mega1 小时前
从零开始搭建 flask 博客实验(4)
后端·python·flask
bcbnb1 小时前
iPhone HTTPS 抓包,从无法抓包到定位问题的流程(Charles/tcpdump/Wireshark/Sniffmaster)
后端
Data_Adventure2 小时前
TypeScript 开发者转向 Java:学习重点与思维迁移指南
后端
吴祖贤2 小时前
Spring AI 零基础入门:从踩坑到上手的完整指南
后端