使用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
相关产品推荐
相关产品推荐

