前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Rust 中的错误处理 - Rust 实践指南

Rust 中的错误处理 - Rust 实践指南

作者头像
niqin.com
发布2022-06-30 16:25:39
8240
发布2022-06-30 16:25:39
举报
文章被收录于专栏:Rust 生态与实践Rust 生态与实践

对于程序员来说,错误处理的重要性是不言而喻的,贯穿于代码编写、开发、调试,以及交付运行的全过程中。对于此等重要的工作,Rust 生态中特别有一个 crate error-chain 对错误处理在 Rust 标准库之上给予了支持。

本文我们通过在 main 方法中对错误适当处理、避免在错误转变过程中遗漏错误、获取复杂错误场景的回溯三个方面来了解 crror-chian crate。

在 main 方法中对错误适当处理

处理尝试打开不存在的文件时发生的错误,是通过使用 error-chain crate 来实现的。error-chain crate 包含大量的模板代码,用于 Rust 中的错误处理。

foreign_links 代码块内的 Io(std::io::Error) 函数允许由 std::io::Error 所报错误信息到 error_chain! 所定义错误类型的自动转换,error_chain! 所定义错误类型将实现 Error trait。

下文的实例将通过打开 Unix 文件 /proc/uptime 并解析内容以获得其中第一个数字,从而告诉系统运行了多长时间。除非出现错误,否则返回正常运行时间。

本书中的其他实例将隐藏 error-chain 模板,如果需要查看,可以通过 ⤢ 按钮展开代码。

代码语言:javascript
复制
use error_chain::error_chain;

use std::fs::File;
use std::io::Read;

error_chain!{
    foreign_links {
        Io(std::io::Error);
        ParseInt(::std::num::ParseIntError);
    }
}

fn read_uptime() -> Result<u64> {
    let mut uptime = String::new();
    File::open("/proc/uptime")?.read_to_string(&mut uptime)?;

    Ok(uptime
        .split('.')
        .next()
        .ok_or("Cannot parse uptime data")?
        .parse()?)
}

fn main() {
    match read_uptime() {
        Ok(uptime) => println!("uptime: {} seconds", uptime),
        Err(err) => eprintln!("error: {}", err),
    };
}

获取复杂错误场景的回溯

本实例展示了如何处理一个复杂的错误场景,并且打印出错误回溯。依赖于 chain_err,通过附加新的错误来扩展错误信息。从而可以展开错误堆栈,这样提供了更好的上下文来理解错误的产生原因。

下述代码尝试将值 256 反序列化为 u8。首先 Serde 产生错误,然后是 csv,最后是用户代码。

代码语言:javascript
复制
use error_chain::error_chain;
use serde::Deserialize;

use std::fmt;

error_chain! {
    foreign_links {
        Reader(csv::Error);
    }
}

#[derive(Debug, Deserialize)]
struct Rgb {
    red: u8,
    blue: u8,
    green: u8,
}

impl Rgb {
    fn from_reader(csv_data: &[u8]) -> Result<Rgb> {
        let color: Rgb = csv::Reader::from_reader(csv_data)
            .deserialize()
            .nth(0)
            .ok_or("Cannot deserialize the first CSV record")?
            .chain_err(|| "Cannot deserialize RGB color")?;

        Ok(color)
    }
}

impl fmt::UpperHex for Rgb {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let hexa = u32::from(self.red) << 16 | u32::from(self.blue) << 8 | u32::from(self.green);
        write!(f, "{:X}", hexa)
    }
}

fn run() -> Result<()> {
    let csv = "red,blue,green
102,256,204";

    let rgb = Rgb::from_reader(csv.as_bytes()).chain_err(|| "Cannot read CSV data")?;
    println!("{:?} to hexadecimal #{:X}", rgb, rgb);

    Ok(())
}

fn main() {
    if let Err(ref errors) = run() {
        eprintln!("Error level - description");
        errors
            .iter()
            .enumerate()
            .for_each(|(index, error)| eprintln!("└> {} - {}", index, error));

        if let Some(backtrace) = errors.backtrace() {
            eprintln!("{:?}", backtrace);
        }

        // In a real use case, errors should handled. For example:
        // ::std::process::exit(1);
    }
}

错误回溯信息如下:

代码语言:javascript
复制
Error level - description
└> 0 - Cannot read CSV data
└> 1 - Cannot deserialize RGB color
└> 2 - CSV deserialize error: record 1 (line: 2, byte: 15): field 1: number too large to fit in target type
└> 3 - field 1: number too large to fit in target type

因公众号篇幅和体验限制,通过附加新的错误来扩展错误信息等实例请点击底部“阅读原文”,或者访问 https://rust-cookbook.budshome.com,按照左侧导航阅读。

以上实例代码都是完整的、可独立运行的程序,因此你可以直接复制它们到自己的项目中进行试验。

如果希望从头了解如何运行上述实例代码,请参考《Rust 实践指南》中关于本书-如何使用本书实例部分。也可以复制链接:http://budshome.com/rust-cookbook/about.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Rust 生态与实践 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档