突然有一天,代码出问题了,而你对此束手无策。对于这种情况,Rust 有 panic! 宏。当执行这个宏时,程序会打印出一个错误信息,展开并清理栈数据,然后接着退出。出现这种情况的场景通常是检测到一些类型的 bug,而且程序员并不清楚该如何处理它。

发生 panic 时的展开或终止

当出现 panic 时,程序默认会开始 展开(unwinding),这意味着 Rust 会回溯栈并清理它遇到的每一个函数的数据,不过这个回溯并清理的过程有很多工作。另一种选择是直接 终止(abort),这会不清理数据就退出程序。那么程序所使用的内存需要由操作系统来清理。如果你需要项目的最终二进制文件越小越好,panic 时通过在 Cargo.toml 的 [profile] 部分增加 panic = ‘abort’,可以由展开切换为终止。例如,如果你想要在release模式中 panic 时直接终止:

[profile.release]
panic = 'abort'

简单的抛出一个panic

使用 panic!

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

控制台打印如下信息:

(base) PS E:\project\hello_cargo> cargo runCompiling hello_cargo v0.1.0 (E:\project\hello_cargo)Finished dev [unoptimized + debuginfo] target(s) in 1.20sRunning `target\debug\hello_cargo.exe`
thread 'main' panicked at 'crash and burn', 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)

错误信息指出错误发生在第2行 第5个字符处。但是我们经常可以引用他人的代码,最终错误会指向别人的 panic! 调用,而不是我们代码中最终导致panic的那一行。对于这种情况,我们可以使用 panic! 被调用的函数的 backtrace 来寻找代码中出问题的地方。下面我们会详细介绍 backtrace 是什么。

使用 panic! 的 backtrace

看一个因为我们的代码而引发别的库中的 panic! 例子:

示例 9-1
fn main() {let v = vec![1, 2, 3];v[99];
}
$ cargo runCompiling panic v0.1.0 (file:///projects/panic)Finished dev [unoptimized + debuginfo] target(s) in 0.27sRunning `target/debug/panic`
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', libcore/slice/mod.rs:2448:10
note: Run with `RUST_BACKTRACE=1` for a backtrace.

可以看到,由于我们的越界访问,造成了缓冲区溢出这个常见的bug。但是错误发生的位置指向了标准库中的 libcore/slice/mod.rs,这是 rust 中 slice 源码实现的地方。也是 panic 真实发生的地方。

并且错误信息还提示我们可以设置 RUST_BACKTRACE 环境变量来得到一个 backtracebacktrace 是一个执行到目前位置所有被调用的函数的列表。Rust 的 backtrace 跟其他语言中的一样:阅读 backtrace 的关键是从头开始读直到发现你编写的文件。这就是问题的发源地。这一行往上是你的代码所调用的代码;往下则是调用你的代码的代码。这些行可能包含核心 Rust 代码,标准库代码或用到的 crate 代码。让我们将 RUST_BACKTRACE 环境变量设置为任何不是 0 的值来获取 backtrace 看看。

RUST_BACKTRACE=1 cargo runFinished dev [unoptimized + debuginfo] target(s) in 0.00sRunning `target/debug/panic`
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', libcore/slice/mod.rs:2448:10
stack backtrace:0: std::sys::unix::backtrace::tracing::imp::unwind_backtraceat libstd/sys/unix/backtrace/tracing/gcc_s.rs:491: std::sys_common::backtrace::printat libstd/sys_common/backtrace.rs:71at libstd/sys_common/backtrace.rs:592: std::panicking::default_hook::{{closure}}at libstd/panicking.rs:2113: std::panicking::default_hookat libstd/panicking.rs:2274: <std::panicking::begin_panic::PanicPayload<A> as core::panic::BoxMeUp>::getat libstd/panicking.rs:4765: std::panicking::continue_panic_fmtat libstd/panicking.rs:3906: std::panicking::try::do_callat libstd/panicking.rs:3257: core::ptr::drop_in_placeat libcore/panicking.rs:778: core::ptr::drop_in_placeat libcore/panicking.rs:599: <usize as core::slice::SliceIndex<[T]>>::indexat libcore/slice/mod.rs:244810: core::slice::<impl core::ops::index::Index<I> for [T]>::indexat libcore/slice/mod.rs:231611: <alloc::vec::Vec<T> as core::ops::index::Index<I>>::indexat liballoc/vec.rs:165312: panic::mainat src/main.rs:413: std::rt::lang_start::{{closure}}at libstd/rt.rs:7414: std::panicking::try::do_callat libstd/rt.rs:59at libstd/panicking.rs:31015: macho_symbol_searchat libpanic_unwind/lib.rs:10216: std::alloc::default_alloc_error_hookat libstd/panicking.rs:289at libstd/panic.rs:392at libstd/rt.rs:5817: std::rt::lang_startat libstd/rt.rs:7418: panic::main

这里有大量的输出!你实际看到的输出可能因不同的操作系统和 Rust 版本而有所不同。为了获取带有这些信息的 backtrace,必须启用 debug 标识。当不使用 --release 参数运行 cargo build 或 cargo run 时 debug 标识会默认启用,就像这里一样。

示例 9-2 的输出中,backtrace 的 12 行指向了我们项目中造成问题的行:src/main.rs 的第 4 行。如果你不希望程序 panic,第一个提到我们编写的代码行的位置是你应该开始调查的,以便查明是什么值如何在这个地方引起了 panic。在示例 9-1 中,我们故意编写会 panic 的代码来演示如何使用 backtrace,修复这个 panic 的方法就是不要尝试在一个只包含三个项的 vector 中请求索引是 100 的元素。当将来你的代码出现了 panic,你需要搞清楚在这特定的场景下代码中执行了什么操作和什么值导致了 panic,以及应当如何处理才能避免这个问题。

本章后面的小节 “panic! 还是不 panic!” 会再次回到 panic! 并讲解何时应该、何时不应该使用 panic! 来处理错误情况。接下来,我们来看看如何使用 Result 来从错误中恢复。

我的RUST学习——【第九章 9-1】panic! 与不可恢复的错误相关推荐

  1. Rust学习第九天——控制测试运行

    并行和连续执行测试 控制测试如何运行 改变cargo test的行为:添加命令行参数 默认行为: 并行运行 所有测试 捕获(不显示)所有输出,使读取与测试结果相关的输出更容易 命令行参数: 针对car ...

  2. Android群英传学习——第九章、Android系统信息与安全机制

    1.Android系统信息获取 1.1 android.os.Build android.os.Build类里面的信息非常丰富,它包含了系统编译时的大量设备.配置信息,下面列举了一些常用的信息: ● ...

  3. C++PrimerPlus学习——第九章编程练习

    前两天有事情去了,没有好好学,之后要补回来 9-1 main.cpp #include <string.h> #include <iostream> #include" ...

  4. java 为什么违例差错控制_JAVA编程思想学习 — 第九章 (违例差错控制)

    1.违例自变量 和 Java 的其他任何对象一样, 需要用 new 在内存堆里创建违例,并需调用一个构建器.在所有标准违例中,存在着两个构建器: 第一个是默认构建器,第二个则需使用一个字串自变量,使我 ...

  5. C语言学习第九章——用户建立自己的数据类型

    结构体 1.c语言允许用户自己建立由不同数据组成的组合型的数据结构,它称为结构体.在其他一些高级语言中称为"记录". 2.定义结构体的一般形式 struct 结构体标记 //str ...

  6. 第九章 神经网络学习-机器学习老师板书-斯坦福吴恩达教授

    第九章 神经网络学习 9.1 代价函数 9.2 反向传播算法 9.3 反向传播直观理解 9.4 使用注意:展开参数 9.5 梯度检测 9.6 随机初始化 9.7 聚在一起 9.8 反向传播例子:自动驾 ...

  7. 机器学习理论《统计学习方法》学习笔记:第九章 EM算法及其推广

    第九章 EM算法及其推广 概述 EM算法 EM算法的收敛性 EM算法实现 K-Means与高斯混合模型 K-Means 高斯混合模型 概述 EM算法是一种迭代算法,1977年由Dempster等人总结 ...

  8. 《Go语言圣经》学习笔记 第九章 基于共享变量的并发

    <Go语言圣经>学习笔记 第九章 基于共享变量的并发 目录 竞争条件 sync.Mutex互斥锁 syn.RWMutex读写锁 内存同步 syn.Once初始化 竞争条件检测 示例:并发的 ...

  9. Android 渗透测试学习手册 第九章 编写渗透测试报告

    第九章 编写渗透测试报告 作者:Aditya Gupta 译者:飞龙 协议:CC BY-NC-SA 4.0 在本章中,我们将学习渗透测试的最终和最重要的方面,撰写报告. 这是一个简短的章节,指导你在报 ...

最新文章

  1. 基于持久内存的 单机上亿(128B)QPS -- 持久化 k/v 存储引擎
  2. SpringCloud服务注册启动的时候报错(com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException)
  3. “新SaaS”引爆产业奇点《2017中国SaaS用户研究报告》
  4. shell模拟php多进程从redis获取数据(多个库)
  5. 大数据分析的5个方面
  6. linux iscsi软件,linux iscsi软件环境搭建
  7. redis-数据类型-普通集合
  8. 小程序 const moment = require('moment')_小程序依赖分析实践
  9. c 结构体转byte_C中结构体和字节流的互换及内存对齐
  10. 初识kbmmw 中的ORM
  11. 程序员的进阶课-架构师之路(15)-那些年你遇到的其他树
  12. 云适配签约比亚迪 构建统一工作平台
  13. android 录屏工具,安卓手机上最好的录屏软件在这里
  14. Facebook 重金悬赏 Hermes 和 Spark AR 漏洞
  15. squid端口转发_Squid服务器三种代理方式详解
  16. code review平台Rietveld应用指南
  17. MLOps- 吴恩达Andrew Ng Data Definition and Baseline Week3 论文等资料汇总
  18. 人工智能、机器学习、神经网络和深度学习的关系
  19. react hooks子给父传值
  20. hdu1166 敌兵布阵(模板题 单点修改 + 区间查询)

热门文章

  1. el-table中使用el-popover点击取消按钮时popover框的显示与隐藏问题
  2. 全国计算机等级考试技巧,必看!全国计算机等级考试的应试技巧
  3. 读书笔记:忍耐的艺术
  4. Redis介绍与安装
  5. PHP随堂笔记时区的设置
  6. 【Linux学习】基本操作
  7. excel 简单制作数据透视表
  8. ubuntu18 编译maplab opencv3_catkin 时出现Flow control statements are not properly nested.
  9. studing method for linux
  10. NLP系列笔记:通俗理解LDA主题模型