• Rust错误处理简介


    Rust错误处理简介

    以下内容总结自 《The Rust Programing Language》

    Rust并不像C++一样使用try catch的异常机制来进行错误处理,他将错误分为可恢复错误和不可恢复错误两类,主要使用panic!宏和Result类型来进行错误处理。

    panic!

    panic!用于处理不可恢复的错误(例如类似c中的段错误)。当出现 panic 时,程序默认会开始 展开(unwinding),这意味着 Rust 会回溯栈并清理它遇到的每 一个函数的数据。

    fn main() {
    	panic!("crash and burn");
        //打印crash ang burn并清理程序栈,
        //若指定panic = 'abort'则,直接中止程序,清理工作交给操作系统
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Result

    Result用于处理可恢复的错误(例如文件打开失败)。

    //T 代表成功时返回的 Ok 成员中的数据的类型
    //E 代表失败时返回的 Err 成员中的错误的类型。
    enum Result<T, E> {
    	Ok(T),
    	Err(E),
    }
    
    //一个简单的使用Result的例子
    use std::fs::File;
    use std::io::ErrorKind;
    fn main() {
    	let f = File::open("hello.txt");
    	let f = match f {
    		Ok(file) => file,
    		Err(error) => match error.kind() {
    			ErrorKind::NotFound => match File::create("hello.txt") {
    				Ok(fc) => fc,
    				Err(e) => panic!("Problem creating the file: {:?}", e),
    			},
    			other_error => {
    			panic!("Problem opening the file: {:?}", other_error)
    			}
    		},
    	};
    }
    
    //Result失败时调用panic的简写:unwrap和expect
    //如果 Result 值是成员 Ok,unwrap 会返回 Ok 中的值。如果 Result 是成员 Err,unwrap 会为我们调用 panic!。
    //expect同理
    fn main() {
    	let f = File::open("hello.txt").unwrap();
        let f = File::open("hello.txt").expect("Failed to open hello.txt");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    传播错误

    当编写一个其实先会调用一些可能会失败的操作的函数时,除了在这个函数中处理错误外,还可以选择 让调用者知道这个错误并决定该如何处理。这被称为 传播(propagating)错误。(即在函数中向上层返回错误,交由上层处理),除常规的return Err外,Rust还提供了?语法糖来编写传播错误代码。

    //常规return Err方式此处从略,下面展示?语法
    use std::fs::File;
    use std::io;
    use std::io::Read;
    //File :: open 调用结尾的 ? 将会把 Ok 中的值返回给变量 f。如果出现了错误,
    //? 运算符会提早返回整个函数并将一些 Err 值传播给调用者。同理也适用于 read_to_string 调用结尾的 ?。
    fn read_username_from_file() -> Result<String, io::Error> {
    	let mut f = File::open("hello.txt")?;
    	let mut s = String::new();
    	f.read_to_string(&mut s)?;
    	Ok(s)
    }
    //甚至可以这样链式调用
    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    注意:

    ? 运算符只能被用于返回值与 ? 作用的值相兼容的函数,所以说对Option或其他类型,如果需要?语法同样适用

    错误处理指导原则

    对于何时适用panic何时适用Result,官方给出了如下指导原则:

    在当有可能会导致有害状态的情况下建议使用 panic! —— 在这里,有害状态是指当一些假设、保证、协 议或不可变性被打破的状态,例如无效的值、自相矛盾的值或者被传递了不存在的值 —— 外加如下几种 情况:

    • 有害状态是非预期的行为,与偶尔会发生的行为相对,比如用户输入了错误格式的数据。

    • 在此之后代码的运行依赖于不处于这种有害状态,而不是在每一步都检查是否有问题。

    • 没有可行的手段来将有害状态信息编码进所使用的类型中的情况

    然而当错误预期会出现时,返回 Result 仍要比调用 panic! 更为合适。这样的例子包括解析器接收到格式 错误的数据,或者 HTTP 请求返回了一个表明触发了限流的状态。在这些例子中,应该通过返回 Result 来表明失败预期是可能的,这样将有害状态向上传播,调用者就可以决定该如何处理这个问题。

    当代码对值进行操作时,应该首先验证值是有效的,并在其无效时 panic!。

  • 相关阅读:
    云原生 | Docker - [Dockerfile]
    JVM启动参数大全及默认值
    关于编辑Windows的右键【新建】删除和添加
    LQ0161 九数分三组【枚举+置换】
    Spring AOP 基于注解源码整理
    Linux学习笔记8
    node_modules包路径查找规则,依赖版本生效规则
    数据结构-难点突破(C++实现树的双亲表示法,孩子表示法,孩子兄弟表示法(树转化为二叉树))
    【广州华锐互动】AR远程连接专家进行协同管理,解放双手让协同更便捷
    英伟达Nvidia论坛
  • 原文地址:https://blog.csdn.net/weixin_45730130/article/details/128064930