rust 错误处理

本文介绍Rust语言中的错误处理机制,包括可恢复错误与不可恢复错误的区别,如何使用Result和panic!宏处理错误,以及如何传播错误。

rust 错误处理概述

  • rust的可靠性:错误处理

    • 大部分情况下:在编译时提示错误
  • 错误的分类

    • 可恢复

      • 例如文件未找到,可再次尝试
    • 不可恢复

      • bug,例如访问的索引超出范围
  • rust没有类似异常的机制

    • 可恢复错误, Result<T, E>
    • 不可恢复错误,panic!宏

不可恢复的错误与panic!

  • 当panic!宏执行:

    • 你的程序会打印一个错误信息
    • 展开(unwind)、清理调用栈(Stack)
    • 退出程序
  • 默认情况下,panic!发生:

    • 程序展开调用栈(工作量大)

      • Rust沿着调用栈往回走
      • 清理每个遇到的函数中的数据
    • 或立即终止调用栈

      • 不进行清理,直接停止程序
      • 内存需要OS进行清理
  • 想让二进制文件更小,把设置从“展开“改为“中止“:

    • 在Cargo.toml中适当的profile部分设置:
      • panic = ‘abort’
[package]
	name = "demo"
	version = "0.1.0"
	authors = ""
	edition = "2018"
[dependencies]
[profile.release]
	panic = 'abort'

使用panic!产出的回溯信息

  • panic!可能出现在:

    • 我们写的代码中
    • 我们所依赖的代码中
  • 可通过调用panic!的函数的回溯信息来定位引起问题的代码

  • 通过设置环境变量RUST_BACKTRACE可得到回溯信息

  • 为了获取带有调试信息的回溯,必须启用调试符号(不带 --release)

Result与可恢复错误

Result枚举

  • enum Result<T, E>{

    ​ Ok(T),

    ​ Err(E),

    }

    T:操作成功情况下,Ok变体里返回的数据类型

    E:操作失败情况下,Err变体里返回的错误的类型

use::fs::File;
fn main(){
	let f = File::open("hello.txt");
}

处理Result的一种方式:match表达式

use std::fs::File;

fn main() {
    let f = File::open("hello.txt");

    let f = match f {
        Ok(file) => file,
        Err(error) => panic!("Problem opening the file: {:?}", error),
    };
}

匹配不同的错误

use std::fs::File;
fn main(){
	let f = File::open("hello.txt");
    let f = match f{
    	Ok(file) => file,
        Err(error) => match error.kind(){
            ErrorKind::NotFind => match File::create("hello.txt"){
                Ok(fc) => fc,
                Err(e) => panic!("Error creating file:{:?}", e),
            },
            other_error => panic!("Error opening the file:{:?}", other_errpr),
        }
    };
}

unwrap:match表达式的一个快捷方法:

  • 如果Result结果是Ok,返回Ok里面的值

  • 如果Result结果是Err,调用panic!宏

use std::fs::File;
fn main(){
    let f = File::open("hello.txt").unwrap();
}

expect:和unwrap类似,但可以指定错误信息

use std::fs::File;
fn main(){
	let f = File::open("hello.txt").expect("文件不存在!");
}

传播错误

  • 在函数出处理错误
  • 将错误返回给调用者
use std::fs::File;
use std::io;
use std::io::read;
fn read_username_from_file() -> Result<String, io::err> {
	let f = File::open("hello.txt");
    let mut f = match f{
        Ok(file) => file,
        Err(e) => return Err(e),
    };
    let mut s = String::new();
    
    match f.read_to_string(&mut s){
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

?运算符

  • ?运算符:传播错误的一种快捷方式
  • 如果Result是Ok:Ok中的值就是表达式的结果,然后继续执行程序
  • 如果Result是Err:Err就是整个函数的返回值,就像使用了return
use std::fs::File;
use std::io;
use std::io::Read;
fn read_username_from_file() -> Result<String, io::Error> {
	let f = File::open("hello.txt")?;
  
    let mut s = String::new();
    
    f.read_to_string(&mut s)?;
    Ok(s)
}

?与from函数

  • Trait std::convert::From 上的from函数:

    • 用于错误之间的转换
  • 当?所应用的错误,会隐式的被from函数处理

  • 当?调用from函数时:

    • 它所接收的错误类型会被转化为当前函数返回类型所定义的错误类型

      EA->EB, EA实现from函数,返回值为EB

  • 用于:针对不同错误原因,返回同一种错误类型

    • 只要每个错误类型实现了转换为所返回的错误类型的from函数

链式调用

use std::fs::File;
use std::io;
use std::io::Read;
fn read_username_from_file() -> Result<String, io::Error> {
	let mut s = String::new();
    
    File::open("hello.txt")?.read_to_string(&mut s)?;
    Ok(s)
}

?运算符只能用于返回值为Result的函数

?运算符与main函数

  • main函数返回类型是:()
  • main函数的返回类型也可以是: Result<T, E>
  • Box 是trait对象:
    • 简单理解:“任何可能的错误类型”

何时使用panic!

总体原则

  • 在定义一个可能失败的函数时,优先考虑返回Result
  • 否则返回panic!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值