• rust从0开始写项目-03-多样话错误处理


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

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

    Part1一、thiserror初体验

    可以使用命令 cargo add thiserror 将它添加到自己的项目中,或者在 Cargo.toml 中添加如下的配置:

    [dependencies]
    thiserror = "1.0"
    • 1

    thiserror 可以用于枚举或者结构体,例如,我们来看一个基本的例子:

    use std::io;
    use log::error;
    use thiserror::Error;
    #[derive(Error,Debug)]
    pub enum DataStoreError {
        #[error("data store disconnected")]
        Disconnect(#[from] std::io::Error),
        #[error("the data for key `{0}` is not available")]
        Redaction(String),
        #[error("invalid header (expected {expected:?},found {found:?})")]
        InvalidHeader {expected:String,found:String},
        #[error("unknown data store error")]
        Unknown
    }

    pub fn error(){
        ///error
        println!("这是没有参数的 Unknown {}",DataStoreError::Unknown);
        println!("这是结构体参数的 InvalidHeader {}",DataStoreError::InvalidHeader {
            expected : String::from("expected"),
            found : String::from("found")
        });
        println!("这是有index参数的 Redaction {}",DataStoreError::Redaction(String::from("Redaction")));
        println!("这是有from参数的 Disconnect {}",DataStoreError::Disconnect(io::Error::from(io::ErrorKind::TimedOut)));

    }
    • 1
    这是没有参数的 Unknown unknown data store error
    这是结构体参数的 InvalidHeader invalid header (expected "expected",found "found")
    这是有index参数的 Redaction the data for key `Redaction` is not available
    这是有from参数的 Disconnect data store disconnected
    • 1

    然后我们来仔细分析下各种用法

    Part2二、#[error]

    如果使用 #[error(...)] 为结构体或者枚举生成自定义错误消息,这将为它们实现 Display

    12.1 Enum

    #[derive(Debug)]
    pub struct Limits{
        lo : i16,
        hi : i16
    }

    #[derive(Error,Debug)]
    pub enum MyError{
        #[error("invalid rdo_lookahead_frames {0} (expected < {})",i8::MAX)]
        InvalidLookahead(u32),
        #[error("first letter must be lowercase but was {:?}",first_char(.0))]
        WrongCase(String),
        #[error("invalid index {idx},expected at least {} and at most {}",.limits.lo,.limits.hi)]
        OutOfBounds{idx:usize,limits:Limits}
    }

    • 1
    pub fn error(){
        println!("这是 enum 的InvalidLookahead {}",MyError::InvalidLookahead(3333));
        //自动调用函数进行比较
        println!("这是 enum 的 WrongCase {}",MyError::WrongCase("kk".to_string()));
        println!("这是 enum 的 OutOfBounds {}",MyError::OutOfBounds{idx : 89,limits:Limits{
            lo:12,
            hi:11
        }});

    }

    这是 enum 的InvalidLookahead invalid rdo_lookahead_frames 3333 (expected < 127)
    这是 enum 的 WrongCase first letter must be lowercase but was 'k'
    这是 enum 的 OutOfBounds invalid index 89,expected at least 12 and at most 11

    • 1

    22.2 struct

    #[derive(Error, Debug)]
    #[error("something failed, msg is: {msg}")]
    pub struct MyErrorStruct {
        msg: &'static str,
    }
    • 1
    println!("这是 struct 的msg  {}",MyErrorStruct{msg:"失败的msg"});


    这是 struct 的msg  something failed, msg is: 失败的msg
    • 1

    32.3 其他结构

    其他结构也是支持的,例如 tuple、空struct 等等

    Part3三、#[from]

    可以使用 #[from] 注解为错误类型实现 From,可以从其他错误生成:

    #[derive(Error, Debug)]
    #[error("some io error happened, {:?}", .source)]
    pub struct MyFromError {
        #[from]
        source: io::Error,
    }
    • 1
    println!("这是 struct 的 from 的 {}",MyFromError::from(io::Error::from(io::ErrorKind::TimedOut)));

    这是 struct 的 from 的 some io error happened, Kind(TimedOut)
    • 1

    Part4四、#[source]

    可以使用 #[source] 属性,或者将字段命名为 source,可为自定义错误实现 source 方法,返回底层的错误类型:

    use std::error::Error;
    use std::io;
    use thiserror::Error;

    #[derive(Error, Debug)]
    pub enum MyError {
      #[error("some io error happened, {:?}", .source)]
      IO { source: io::Error },
    }

    fn main() {
      let err = MyError::IO {
          source: io::Error::from(io::ErrorKind::TimedOut),
      };
      println!("{:?}", err.source());
    }


    • 1

    或者使用 #[source] 属性标记非 source 的字段,例如:这里是 err 字段:

    use std::error::Error;
    use std::io;
    use thiserror::Error;

    #[derive(Error, Debug)]
    pub enum MyError {
      #[error("some io error happened, {:?}", .err)]
      IO {
          #[source]
          err: io::Error,
      },
    }

    fn main() {
      let err = MyError::IO {
          err: io::Error::from(io::ErrorKind::TimedOut),
      };
      println!("{:?}", err.source());
    }
    • 1

    #[from]#[source] 二选一即可,#[from] 也会为类型生成 .source() 方法,例如:

    #![allow(unused)]
    #![feature(backtrace)]

    use std::backtrace;
    use std::error::Error as _;
    use std::io;
    use thiserror::Error;

    #[derive(Error, Debug)]
    #[error("some io error happened, {:?}", .source)]
    pub struct MyError {
      #[from]
      source: io::Error,
      backtrace: backtrace::Backtrace,
    }

    fn main() {
      let err = MyError::from(io::Error::from(io::ErrorKind::TimedOut));
      println!("{:?}", err.source());
    }
    • 1

    Part5五、#[backtrace]

    只要在我们的错误结构体里面放个类型为 std::backtrace::Backtrace 的字段,就会自动实现 backtrace() 方法,可以看 #[from]

    另外,如果使用 #[backtrace] 标记 sourcesource 字段,或者 #[source],或者 #[from]),那么 backtrace() 方法会转发到 sourcebacktrace

    Part6六、#[error(transparent)]

    可以通过 #[error(transparent)]sourceDisplay 直接使用底层的错误,这对于那些想处理任何的类型来说是很有用的:

    use std::io;
    use log::error;
    use thiserror::Error;
    use anyhow::anyhow;
    use std::error::Error as _;
    #[derive(Error,

    #[derive(Error, Debug)]
    #[error(transparent)]
    pub struct MyErrorTrans {
        #[from]
        source: anyhow::Error,
    }

    #[derive(Error, Debug)]
    pub enum MyErrorTransEnum {
        #[error("file not found")]
        FileNotFound,
        #[error(transparent)]
        Other(#[from] anyhow::Error), // source and Display delegate to anyhow::Error
    }

    • 1
    //transparent
    let err = MyErrorTrans::from(anyhow!("Missing attribute: {}""field1"));
    println!("{}", err);
    println!("{:?}", err);

    let err = MyErrorTransEnum::from(anyhow!("Missing attribute: {}""field1"));
    println!("{}", err);
    println!("{:?}", err);

    Missing attribute: field1
    MyErrorTrans { source: Missing attribute: field1 }
    Missing attribute: field1
    Other(Missing attribute: field1)
    • 1

    本文由 mdnice 多平台发布

  • 相关阅读:
    Python编程基础:函数的使用
    使用 Docker Compose 部署 RabbitMQ 的一些经验与踩坑记录
    excel学习
    2023/9/6 -- C++/QT
    全网最清楚的:Spring Boot 启动流程讲解
    前后端协议后端统一返回格式Result
    React为什么要使用Hooks以及个人的一些理解
    Primavera P6 Professional 21.12 登录异常案例分享
    VSCode连接远程服务器及docker
    关于游戏介绍的HTML网页设计 HTML5期末考核大作业 HTML静态游戏网页作业 web前端开发技术 web课程设计 网页规划与设计
  • 原文地址:https://blog.csdn.net/qq_39787367/article/details/134292424