You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Rust的catch_unwind时遇“may not be safely transferred across an unwind boundary”错误

Rust中使用panic::catch_unwind捕获panic的编译错误解决方法

问题描述

测试Rust的panic捕获功能时,编写了如下代码:

use std::panic;

fn create_greeting(name: &str) -> String {
    //panic!("Oh no, something went wrong!");
    let greeting = format!("Hello, {}!", name);
    return greeting;
}

fn main() {
    let mut msg: String;
    let result = panic::catch_unwind(|| {
        let name = "Alice";
        msg = create_greeting(name);
    });

    match result {
        Ok(_) => {
            println!("{}", msg);
        }
        Err(_) => {
            println!("A panic occurred and was caught");
        }
    }
}

需求是调用可能触发panic的create_greeting函数,正常执行时打印结果,发生panic时提示错误,但编译时遇到如下错误:

error[E0277]: the type `&mut String` may not be safely transferred across an unwind boundary
   --> src/main.rs:11:38
    |
11  |       let result = panic::catch_unwind(|| {
    |                    ------------------- ^-
    |                    |                   |
    |  __________________|___________________within this `{closure@src/main.rs:11:38: 11:40}`
    | |                  |
    | |                  required by a bound introduced by this call
12  | |         let name = "Alice";
13  | |         msg= create_greeting(name);
14  | |     });
    | |_____^ `&mut String` may not be safely transferred across an unwind boundary

错误原因

panic::catch_unwind要求传入的闭包必须实现UnwindSafe trait,这个 trait 用于保证闭包捕获的变量在跨 unwind 边界时不会引发内存安全问题。你的闭包捕获了外部的可变引用&mut String(即msg的可变借用),而这种类型默认不满足UnwindSafe——如果panic发生在赋值过程中,msg可能处于未初始化或不一致的状态,传递这种状态会存在安全风险。

解决方案

方案一:让闭包返回结果(推荐)

直接让闭包返回create_greeting的执行结果,避免捕获外部可变变量,这样闭包自然满足UnwindSafe要求:

use std::panic;

fn create_greeting(name: &str) -> String {
    // panic!("Oh no, something went wrong!");
    format!("Hello, {}!", name)
}

fn main() {
    let result = panic::catch_unwind(|| {
        let name = "Alice";
        create_greeting(name)
    });

    match result {
        Ok(msg) => println!("{}", msg),
        Err(_) => println!("A panic occurred and was caught"),
    }
}

catch_unwind会将正常执行的结果包裹在Ok中返回,直接在match分支处理即可,逻辑更清晰,也符合Rust的安全规范。

方案二:手动标记闭包为UnwindSafe(仅必要时使用)

如果必须捕获外部可变变量(比如复杂场景下无法通过返回值传递结果),可以使用AssertUnwindSafe包装闭包,手动标记其为安全的。但需要自行保证:即使panic发生,捕获的变量状态不会引发安全问题。

use std::panic::{self, AssertUnwindSafe};

fn create_greeting(name: &str) -> String {
    // panic!("Oh no, something went wrong!");
    format!("Hello, {}!", name)
}

fn main() {
    let mut msg = String::new();
    let result = panic::catch_unwind(AssertUnwindSafe(|| {
        let name = "Alice";
        msg = create_greeting(name);
    }));

    match result {
        Ok(_) => println!("{}", msg),
        Err(_) => println!("A panic occurred and was caught"),
    }
}

在这个例子中,msg仅被赋值操作覆盖,panic要么发生在赋值前(此时msg是空字符串),要么赋值完成后,不会处于中间不一致状态,因此使用AssertUnwindSafe是安全的。

内容的提问来源于stack exchange,提问作者fgalan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 18:52:54