广告
返回顶部
首页 > 资讯 > 精选 >Rust处理错误的方法是什么
  • 314
分享到

Rust处理错误的方法是什么

2023-07-05 19:07:34 314人浏览 泡泡鱼
摘要

这篇文章主要介绍“Rust处理错误的方法是什么”,在日常操作中,相信很多人在Rust处理错误的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Rust处理错误的方法是什么”的疑惑有所帮助!接下来,请跟

这篇文章主要介绍“Rust处理错误的方法是什么”,在日常操作中,相信很多人在Rust处理错误的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Rust处理错误的方法是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

    错误处理

    Rust 中的错误主要分为两类:

    • 可恢复错误,通常用于从系统全局角度来看可以接受的错误,例如处理用户的访问、操作等错误,这些错误只会影响某个用户自身的操作进程,而不会对系统的全局稳定性产生影响

    • 不可恢复错误,刚好相反,该错误通常是全局性或者系统性的错误,例如数组越界访问,系统启动时发生了影响启动流程的错误等等,这些错误的影响往往对于系统来说是致命的

    不可恢复错误

    不可恢复错误通常是非常严重的,例如:程序一开始读取配置文件失败或者连接数据库失败,诸如此类导致程序运行发生致命错误的,可以使用不可恢复错误。在rust中,触发不可恢复错误使用panic即可。

    触发panic可以分为被动触发和主动调用两种方式。

    被动触发

    下面是一个被动触发panic的例子。

    fn main() {    let v = vec![1, 2, 3];    v[99];}

    这段代码由于数组越界访问,导致被动触发了panic。错误信息如下所示:

    thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:4:5
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

    backtrace栈展开

    可以注意到上面的note提示我们在run的时候使用RUST_BACKTRACE=1来进行栈回溯,它包含了函数调用的顺序。例如:

     RUST_BACKTRACE=1 carGo run

    执行以后输出的错误如下所示:

    thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:4:5
    stack backtrace:
    0: rust_begin_unwind
              at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/std/src/panicking.rs:575:5
    1: core::panicking::panic_fmt
              at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/panicking.rs:64:14
    2: core::panicking::panic_bounds_check
              at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/panicking.rs:147:5
    3: <usize as core::slice::index::SliceIndex<[T]>>::index
              at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/slice/index.rs:260:10
    4: core::slice::index::<impl core::ops::index::Index<I> for [T]>::index
              at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/slice/index.rs:18:9
    5: <alloc::vec::Vec<T,A> as core::ops::index::Index<I>>::index
              at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/alloc/src/vec/mod.rs:2727:9
    6: error_handling::main
              at ./src/main.rs:4:5
    7: core::ops::function::FnOnce::call_once
              at /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/core/src/ops/function.rs:507:5
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

    最近调用的函数排在列表的最上方。因为咱们的 main 函数基本是最先调用的函数了,所以排在了倒数第二位,还有一个关注点,排在最顶部最后一个调用的函数是 rust_begin_unwind,该函数的目的就是进行栈展开,呈现这些列表信息给我们。

    要获取到栈回溯信息,你还需要开启 debug 标志,该标志在使用 cargo run 或者 cargo build 时自动开启(这两个操作默认是 Debug 运行方式)。同时,栈展开信息在不同操作系统或者 Rust 版本上也有所不同。

    panic时的两种终止方式

    当出现 panic! 时,程序提供了两种方式来处理终止流程:栈展开和直接终止。

    其中,默认的方式就是 栈展开,这意味着 Rust 会回溯栈上数据和函数调用,因此也意味着更多的善后工作,好处是可以给出充分的报错信息和栈调用信息,便于事后的问题复盘。直接终止,顾名思义,不清理数据就直接退出程序,善后工作交与操作系统来负责。

    对于绝大多数用户,使用默认选择是最好的,但是当你关心最终编译出的二进制可执行文件大小时,那么可以尝试去使用直接终止的方式,例如下面的配置修改 Cargo.toml 文件,实现在 release 模式下遇到 panic 直接终止:

    [profile.release]
    panic = 'abort'

    主动调用panic

    在某些特殊场景中,开发者想要主动抛出一个异常。rust提供了panic!宏,它可以在你调用时,打印出一个错误信息,展开报错点往前的函数调用堆栈,最后退出程序。一定是不可恢复的错误,才调用 panic! 处理,你总不想系统仅仅因为用户随便传入一个非法参数就崩溃吧?所以,只有当你不知道该如何处理时,再去调用 panic!

    fn main() {    panic!("crash");}

    运行后输出:

    thread 'main' panicked at 'crash', src/main.rs:8:5
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

    它告诉我们,main 函数所在的线程崩溃了,发生的代码位置是 src/main.rs 中的第 8 行第 5 个字符(去除该行前面的空字符)

    线程panic后程序是否会终止

    如果是 main 线程,则程序会终止,如果是其它子线程,该线程会终止,但是不会影响 main 线程。因此,尽量不要在 main 线程中做太多任务,将这些任务交由子线程去做,就算子线程 panic 也不会导致整个程序的结束。

    Result枚举类型

    它被定义为如下:

    enum Result<T, E> {    Ok(T),    Err(E),}

    泛型参数 T 代表成功时存入的正确值的类型,存放方式是 Ok(T),E 代表错误时存入的错误值,存放方式是 Err(E)。一个实际的例子如下:

    #![allow(unused)]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)        },    };}

    代码很清晰,对打开文件后的 Result<T, E> 类型进行匹配取值,如果是成功,则将 Ok(file) 中存放的的文件句柄 file 赋值给 f,如果失败,则将 Err(error) 中存放的错误信息 error 使用 panic 抛出来,进而结束程序。

    直接 panic 还是过于粗暴,因为实际上 IO 的错误有很多种,我们需要对部分错误进行特殊处理,而不是所有错误都直接崩溃:

    #![allow(unused)]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),        },    };}

    上面代码在匹配出 error 后,又对 error 进行了详细的匹配解析,最终结果:

    如果是文件不存在错误 ErrorKind::NotFound,就创建文件,这里创建文件File::create 也是返回 Result,因此继续用 match 对其结果进行处理:创建成功,将新的文件句柄赋值给 f,如果失败,则 panic

    剩下的错误,一律 panic.

    unwrap和expect

    它们的作用就是,如果返回成功,就将 Ok(T) 中的值取出来,如果失败,就直接 panic。例如:

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

    如果hello.txt不存在,则会导致panic;而expect会带上自定义的错误提示信息,相当于重载了错误打印的函数:

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

    如果hello.txt不存在,那么panic的时候expect会带上自定义的错误提示信息“Failed to open hello.txt”。

    传播错误

    rust提供了错误传递的方式,以满足不同的编程风格来处理错误。有的人喜欢原地处理,有的人则是需要将错误传递到上层调用处进行处理。rust提供了?来进行错误传播。例如:

    #![allow(unused)]fn main() {use std::fs::File;use std::io;use std::io::Read;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)}let res = read_username_from_file();dbg!(&res);}

    我们在此处进行了错误传递,当前目录下不存在hello.txt是,?会把发生的错误传递到上层,也是就是调用read_username_from_file处,错误结果保存在res中。输出如下所示:

    [src/main.rs:64] &res = Err(    Os {        code: 2,        kind: NotFound,        message: "No such file or directory",    },)

    详细的显示了错误信息,包含错误码code,错误种类kind,错误消息message。?其实是一个宏。当使用 ? 运算符时,如果表达式的结果是一个错误值,那么整个函数将立即返回这个错误值,否则会将表达式的结果进行包装并继续执行函数。?的强大之处在于自动类型提升,例如:

    fn main() {fn open_file() -> Result<File, Box<dyn std::error::Error>> {    let mut f = File::open("hello.txt")?;    Ok(f)}let res = open_file();dbg!(&res);}

    当前目录下没有hello.txt时,open会失败,此时发送的错误是std::io::Error 类型,但是 open_file 函数返回的错误类型是 std::error::Error 的特征对象。标准库中定义的 From 特征,该特征有一个方法 from,用于把一个类型转成另外一个类型,? 可以自动调用该方法,然后进行隐式类型转换。因此只要函数返回的错误 ReturnError 实现了 From<OtherError> 特征,那么 ? 就会自动把 OtherError 转换为 ReturnError。除此之外,?还可以实现链式调用。例如:

    #![allow(unused)]fn main() {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)}}

    确实牛逼,这样就不用写一大堆代码来处理错误了。

    ?用于Option返回

    ? 不仅仅可以用于 Result 的传播,还能用于 Option 的传播。

    fn main() {fn last_char_of_first_line(text: &str) -> Option<char> {    text.lines().next()?.chars().last()}let res = last_char_of_first_line("123");dbg!(&res);}

    如果next返回的是None,那么执行结束,直接返回None,否则接着进行链式调用。

    带返回值的 main 函数

    在了解了 ? 的使用限制后,这段代码你很容易看出它无法编译:

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

    因为 ? 要求 Result<T, E> 形式的返回值,而 main 函数的返回是 (),怎么办?实际上 Rust 还支持另外一种形式的 main 函数:

    use std::error::Error;use std::fs::File;fn main() -> Result<(), Box<dyn Error>> {    let f = File::open("hello.txt")?;    Ok(())}

    这样就能使用 ? 提前返回了,同时我们又一次看到了Box<dyn Error> 特征对象,因为 std::error:Error 是 Rust 中抽象层次最高的错误,其它标准库中的错误都实现了该特征,因此我们可以用该特征对象代表一切错误,就算 main 函数中调用任何标准库函数发生错误,都可以通过 Box<dyn Error>这个特征对象进行返回.

    到此,关于“Rust处理错误的方法是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

    --结束END--

    本文标题: Rust处理错误的方法是什么

    本文链接: https://www.lsjlt.com/news/354528.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • Rust处理错误的方法是什么
      这篇文章主要介绍“Rust处理错误的方法是什么”,在日常操作中,相信很多人在Rust处理错误的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Rust处理错误的方法是什么”的疑惑有所帮助!接下来,请跟...
      99+
      2023-07-05
    • Rust是怎么处理错误的
      本文小编为大家详细介绍“Rust是怎么处理错误的”,内容详细,步骤清晰,细节处理妥当,希望这篇“Rust是怎么处理错误的”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。异常的演进程序在运行的过程中,总是会不可避免地...
      99+
      2023-07-04
    • GoFrame错误处理常用方法是什么
      这篇“GoFrame错误处理常用方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“GoFrame错误处理常用方法是什么...
      99+
      2023-07-02
    • access数据库错误处理的方法是什么
      在Access数据库中,可以使用以下方法处理错误:1. 使用On Error语句:在代码中使用On Error语句,可以捕捉并处理运...
      99+
      2023-09-21
      access数据库
    • Java事件与错误处理方法是什么
      这篇文章主要讲解了“Java事件与错误处理方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java事件与错误处理方法是什么”吧!  12.1事件处理  传授新知  消息驱动、事件处理...
      99+
      2023-06-03
    • mysql相关的错误问题处理方法是什么
      这篇文章主要讲解了“mysql相关的错误问题处理方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mysql相关的错误问题处理方法是什么”吧! ...
      99+
      2022-10-19
    • Angular中处理错误的方式是什么
      本篇内容主要讲解“Angular中处理错误的方式是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Angular中处理错误的方式是什么”吧!什么是Angula...
      99+
      2022-10-19
    • swift错误处理do catch try try!使用的方法是什么
      这篇“swift错误处理do catch try try!使用的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获...
      99+
      2023-07-05
    • php 404错误的常见原因和处理方法是什么
      这篇文章主要介绍了php 404错误的常见原因和处理方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇php 404错误的常见原因和处理方法是什么文章都会有所收获,下面我们一起来看看吧。一、常见原因文件或...
      99+
      2023-07-05
    • java中HttpClient的错误处理方法
      这篇“java中HttpClient的错误处理方法”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“java中HttpClien...
      99+
      2023-06-30
    • JavaScript常见的错误处理方法
      这篇文章主要介绍“JavaScript常见的错误处理方法”,在日常操作中,相信很多人在JavaScript常见的错误处理方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Ja...
      99+
      2022-10-19
    • javascript全局错误的处理方法
      这篇文章主要介绍了javascript全局错误的处理方法,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。JavaScript是什么JavaScript是一种直译式的脚本语言,其...
      99+
      2023-06-14
    • Node.js的错误处理机制是什么
      本篇内容介绍了“Node.js的错误处理机制是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Node.js 是一个基于 Chrome V...
      99+
      2023-07-05
    • go语言规范RESTful API业务错误处理的方法是什么
      这篇“go语言规范RESTful API业务错误处理的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“go...
      99+
      2023-07-05
    • Kali Too many open files 错误处理办法是什么
      本篇文章为大家展示了Kali  Too many open files 错误处理办法是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。最近试用Kali,在使用hydra的时候,发现一直出...
      99+
      2023-06-13
    • springmvc错误处理机制是什么
      这篇“springmvc错误处理机制是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“springmvc错误处理机制是什么...
      99+
      2023-06-17
    • mybatis错误处理的方法有哪些
      MyBatis 提供了以下几种错误处理的方法:1. 异常映射:MyBatis 可以将底层数据库访问引发的异常映射为应用程序定义的异常...
      99+
      2023-09-13
      mybatis
    • java错误处理的方法有哪些
      Java错误处理的方法有以下几种:1. 异常捕获和处理:使用try-catch语句来捕获和处理异常。在try块中编写可能抛出异常的代...
      99+
      2023-08-26
      java
    • python错误处理的方法有哪些
      在Python中,常用的错误处理方法有以下几种: try-except语句:用于捕获和处理异常。代码放在try代码块中执行,如果...
      99+
      2023-10-26
      python
    • PHP中的错误处理机制是什么?
      PHP是一种流行而强大的服务器端编程语言,可以用来开发各种Web应用程序。就像其他编程语言一样,PHP也有可能会出现错误和异常。这些错误和异常可能由各种原因引起,如程序错误、服务器错误、用户输入错误等等。为了确保程序的运行稳定性和可靠性,P...
      99+
      2023-05-14
      PHP错误处理 异常处理 错误日志记录
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作