#[panic_handler]

#[panic_handler]用于定义panic!#![no_std]程序中的行为。#[panic_handler]必须应用于签名为fn(&PanicInfo) -> !的函数,并且这样的函数仅能在一个二进制程序/动态链接库的整个依赖图中仅出现一次。PanicInfo的 API 可以在 API docs 中找到。

鉴于#![no_std]应用程序没有标准的输出,并且一些#![no_std]应用程序,例如嵌入式应用程序,在开发和发布时需要不同的 panic 行为,因此拥有专门的 panic crate,即只包含#[panic_handler]的 crate 是有帮助的。这样,应用程序可以通过简单地链接到一个不同的 panic crate 来轻松地选择 panic 行为。

下面是一个例子,根据使用开发配置文件(cargo build)或使用发布配置文件(cargo build --release)编译的应用程序具有不同的恐慌行为:

panic-semihostingcrate —— 使用 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();

    // 输出日志: "panicked at '$reason', src/main.rs:27:4" 
    writeln!(host_stderr, "{}", info).ok();

    loop {}
}

panic-haltcrate —— 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() {
    // ..
}