#[panic_handler]
#[panic_handler] 用于定义 #![no_std] 应用中 panic! 的行为。#[panic_handler] 属性必须应用于签名形如 fn(&PanicInfo) -> ! 的函数,并且该函数在二进制 / dylib / cdylib crate 的依赖图中必须**只出现一次**。PanicInfo 的 API 可以在 API 文档 中找到。
考虑到 #![no_std] 应用没有**标准**输出,并且一些 #![no_std] 应用(例如嵌入式应用)在开发和发布时需要不同的 panicking(panic 处理)行为,拥有 panic crate(只包含 #[panic_handler] 的 crate)会很有帮助。这样,应用只需链接到不同的 panic crate 就可以轻松切换 panicking 行为。
下面展示了一个示例,其中应用的 panicking 行为取决于它是使用开发配置文件 (cargo build) 还是发布配置文件 (cargo build --release) 进行编译。
panic-semihosting crate -- 使用 semihosting 将 panic 消息记录到主机 stderr
#![no_std]
use core::fmt::{Write, self};
use core::panic::PanicInfo;
struct HStderr {
// ..
_0: (),
}
impl HStderr {
fn new() -> HStderr { HStderr { _0: () } }
}
impl fmt::Write for HStderr {
fn write_str(&mut self, _: &str) -> fmt::Result { Ok(()) }
}
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
let mut host_stderr = HStderr::new();
// logs "panicked at '$reason', src/main.rs:27:4" to the host stderr
writeln!(host_stderr, "{}", info).ok();
loop {}
}
panic-halt crate -- 在 panic 时暂停线程;消息被丢弃
#![no_std]
use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
app crate
#![no_std]
// dev profile
#[cfg(debug_assertions)]
extern crate panic_semihosting;
// release profile
#[cfg(not(debug_assertions))]
extern crate panic_halt;
fn main() {
// ..
}