首页 > 其他分享 >18_rust的错误处理

18_rust的错误处理

时间:2023-10-25 17:44:32浏览次数:33  
标签:std Err rs 18 Result 错误处理 main panic rust

错误处理

不可恢复的错误与panic!宏

rust语言的错误处理:

  • rust语言具有较高的可靠性,有完备的错误处理机制,大部分情况下,能在编译是提示错误,并处理完错误。
  • rust没有类似异常处理的机制

错误的分类:

  • 可恢复错误:使用Result<T, E>机制,如文件未找到,可再次尝试。
  • 不可恢复:bug,使用panic!宏处理,当执行该宏时,程序立即终止,如索引越界访问。

当panic!宏执行时:

  • 程序会打印一个错误信息
  • 展开(unwind)、清理调用栈(Stack)
  • 退出程序

为应对panic,展开或中止(abort)调用栈。
默认情况下,当panic发生时,会执行:

  • 程序展开调用栈(工作量大):rust沿着调用栈往回走,清理每个遇到的函数中的数据。
  • 或立即中止调用栈:不进行清理,直接停止程序,内存则需要OS进行清理。

如果想让二进制文件更小,可把设置从“展开”改为“中止”:

  • 在Cargo.toml中适当的profile部分设置:panic = 'abort'
[profile.release]
panic = 'abort'

使用panic!产生的回溯信息

  • panic!可能出现在自己开发的代码和依赖的代码中,可通过panic!函数回溯信息来定位引起问题的代码。
  • 可通过设置环境变量RUST_BACKTRACE获得回溯信息。
  • 为了获取带有调试信息的回溯,必须启用调试符号(执行Cargo run命令时不带 --release)。
fn main() {
    panic!("panic test");
}
/* 运行结果:
thread 'main' panicked at 'panic test', src\main.rs:2:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\hello_cargo.exe` (exit code: 101)
*/

另一个例子:

fn main() {
    let v = vec![1, 2];
    v[5];
}
/* 运行结果:
thread 'main' panicked at 'index out of bounds: the len is 2 but the index is 5', src\main.rs:3:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
*/

根据提示,如果设置RUST_BACKTRACE=1环境变量就可显示backtrace,就可看到真正发生panic的地方了

>set RUST_BACKTRACE=1 && cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target\debug\hello_cargo.exe`
thread 'main' panicked at 'index out of bounds: the len is 2 but the index is 5', src\main.rs:3:5
stack backtrace:
   0: std::panicking::begin_panic_handler
             at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library\std\src\panicking.rs:593
   1: core::panicking::panic_fmt
             at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library\core\src\panicking.rs:67
   2: core::panicking::panic_bounds_check
             at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library\core\src\panicking.rs:162
   3: core::slice::index::impl$2::index<i32>
             at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be\library\core\src\slice\index.rs:261
   4: alloc::vec::impl$12::index<i32,usize,alloc::alloc::Global>
             at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be\library\alloc\src\vec\mod.rs:2675
   5: hello_cargo::main
             at .\src\main.rs:3
   6: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
             at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be\library\core\src\ops\function.rs:250
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: process didn't exit successfully: `target\debug\hello_cargo.exe` (exit code: 101)

可见第5个栈信息是测试代码,其他是库代码。提示显示可设置RUST_BACKTRACE=full可获得一详细的backtrace。

可恢复的错误与Result

通常情况下,会对程序运行可能的错误进行处理,而不是让程序终止运行,而且很多错误也是通过一定处理后便可继续运行,rust中采用Result枚举来处理错误。

Result枚举的定义

enum Result<T, E> {
  OK(T),
  Err(E),
}
  • T: 操作成功的情况,OK变体里返回数据的类型。
  • E:操作失败的情况,Err变体里返回错误的类型。

处理Result的一种方式:使用match表达式
和Option枚举一样,Result及其变体也是由prelude带入作用域的,所以使用OK和Err变体时不需要写成Result::OK的格式了。

use std::fs::File;
fn main() {
    let f = File::open("test.txt"); // 返回值就是个Result类型,std::result::Result<std::fs::File, std::io::Error>类型
    // 打开文件可能发生文件不存在的错误,如果成功则返回std::fs::File类型,不存在或无权限等导致不成功则返回io::Err错误
    let fp = match f {
        Ok(file) => file, // 如果成功则返回file实体,使得fp = file
        Err(error) => {
            panic!("Err msg: {:?}", error) // 这里可不用;号,加上也可
        },
    };
}
// 运行结果:thread 'main' panicked at 'Err msg: Os { code: 2, kind: NotFound, message: "系统找不到指定的文件。" }', src\main.rs:8:13

还可匹配不同的错误
如上述文件打开可能的错误是std::io::Error类型,也是一个struct,提供一错误类型方法kind(),返回值是一std::io::ErrorKind枚举,里边的变体用于描述可能发生IO错误,比如NotFound错误。

use std::fs::File;
use std::io::ErrorKind;

fn main() {
    let f = File::open("test.txt");
    let fp = match f {
        Ok(file) => file,
        Err(error) => match error.kind() { // 如果打开失败则创建文件
            ErrorKind::NotFound => match File::create("test.txt") { // 创建也可能失败,所以需要继续match
                Ok(fc) => fc,
                Err(e) => panic!("Err creat file: {:?}", e),
            },
            other_err => panic!("Err open file: {:?}", other_err),
        },
    };
}

运行结果是在项目目录下创建了一个文件test.txt。

上述代码中使用了很多match,代码很原始,可使用闭包(closure)。
Result<T, E>有很多方法:可接收闭包作为参数,使用match实现,可使上述代码更简洁,减少match嵌套。

use std::fs::File;
use std::io::ErrorKind;
fn main() {
    let f = File::open("test.txt").unwrap_or_else(|error| {
        if error.kind() == ErrorKind::NotFound {
            File::create("test.txt").unwrap_or_else(|error| {
                panic!("err create file: {:?}", error);
            })
        } else {
            panic!("Err open file: {:?}", error);
        }
    });
}

unwrap方法

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

标签:std,Err,rs,18,Result,错误处理,main,panic,rust
From: https://www.cnblogs.com/UFO-blogs/p/17787788.html

相关文章

  • CF1884D
    传送门description给定长度为\(n\)的数组\(c\)。求公因数都不在数组里的有序元素对\((c_i,c_j),i<j\)的个数。\(n\leq10^6\),值域\(n\)solution不妨先计算存在公因数且是无序对且允许\(i=j\)的个数,最后容斥一下。设数组里有\(a_i\)个\(i\),\(b_i\)表示\(i\)的......
  • Window 上 VS Code 无法编译Rust 文件的错误
    Window上VSCode无法编译Rust文件的错误error:linker`link.exe`notfound在CMD中运行以下命令1.rustuptoolchaininstallstable-x86_64-pc-windows-gnu2.rustupdefaultstable-x86_64-pc-windows-gnu参考:https://blog.csdn.net/Libigtong/article/details/131823204......
  • CF1854E Games Bundles 题解
    乱搞题设个\(dp[i]\)表示和为\(i\)的子序列个数,那么转移是容易的,\(dp[j]+=dp[j-i]\),然后就判下\(dp[60]+dp[60-i]\)是否大于\(m\),发现这样子搞对于比较大的数可能达不到\(m\)的限制,因为这样子转移,默认的是一个数只选一次,但是我们可以重复选,这启发我们需要设定一个值......
  • 18.1 Socket 原生套接字抓包
    原生套接字抓包的实现原理依赖于Windows系统中提供的ioctlsocket函数,该函数可将指定的网卡设置为混杂模式,网卡混杂模式(PromiscuousMode)是常用于计算机网络抓包的一种模式,也称为监听模式。在混杂模式下,网卡可以收到经过主机的所有数据包,而非只接收它所对应的MAC地址的数据包。一......
  • CF1878B题解
    CF1878BAleksaandStack题目翻译给定\(n\),试构造一个长度为\(n\)的严格上升正整数序列\(a_1,a_2,a_3,...,a_n\)使得\(\foralli\in[3,n],(a_{i-1}+a_{i-2})\nmid3a_i\)。单个测试点内包含多组测试数据。思路拿到题目,发现不好一个数一个数地构造,考虑......
  • USACO2018(铂金组)
    前言:教练给我们做铂金组的题目真的抬举我们了……[USACO18OPEN]DisruptionP题目描述:你有一棵节点数为\(n\),边数为\(n-1\)的树。然后你会给这棵树新增加\(m\)条边,对于每条边,有\(u,v,w\)分别表示边连接的两个节点分别为\(u\)和\(v\),和一个边权\(w\)。每次删掉一条......
  • CF1887C Minimum Array
    一个很直接的思路是,维护当前可行决策集合\(S\in\{0,\dots,q\}\),从\(1\)到\(n\)分别考虑每一个\(a\),排除一些决策,最终得到答案。既然要排除决策,我们当然需要知道对于当前的\(a_i\),前\(j\)个操作之后的值都是多少,如果能得到这个,且这些值都在线段树上呈现,我们直接在线段树......
  • CF1887E Good Colorings
    矩形的四个角颜色不同是个很难描述的条件,不妨利用行列二元关系转化,将\((x,y)\)颜色为\(c\)改为在\(x\)和\(y\)之间连接边权为\(c\)的边,则四角颜色不同就被我们转化为了,存在一个边权各不相同的四元环。此时把特殊条件【初始给定\(2n\)个格子\(2n\)个不同颜色】放在......
  • Codeforces 1862G 题解
    传送门题解因为有这个操作:将序列\(a\)加上\(\{n,n-1,\cdots,1\}\),考虑差分。那么显然每次操作会将差分数组中的每个元素减去\(1\),如果差分数组中有\(0\),就会把\(0\)删除。所以可以发现差分数组中剩下的一定是操作前的最大值。由于操作后最大值还是最大值,最小值仍......
  • QCN9074-6E Throughput Test Report in DR6018
    IPQ6010+QCN9074|QCN9074-6EThroughputTestReportinDR6018AreyoucuriousabouttheperformancecapabilitiesoftheQCN9074-6EnetworkcardintheDR6018?Looknofurther!Inthisblog,we'llwalkyouthroughthehardwareyou'llneed,howtose......