尝试获取Cell内部值时遇到无法移出可变引用的Rust错误
问题解决:Cell引用下的可变借用错误
错误信息
编译时触发如下错误:
error[E0596]: cannot borrow `*data` as mutable, as it is behind a `&` reference --> src\stack.rs:17:28 | 17 | file_dir.push_str(&data.get_mut().unwrap()); | ^^^^^^^^^^^^^^ `data` is a `&` reference, so the data it refers to cannot be borrowed as mutable | help: consider changing this to be a mutable reference | 16 | PANIC_ERROR_OUTPUT.with(|data: &mut Cell<Option<String>>| { | +++
尝试将data改为可变引用会出现类型不匹配,解引用和克隆操作也未能解决问题。
完整代码片段
use std::cell::Cell; thread_local! { pub static PANIC_ERROR_OUTPUT: Cell<Option<String>> = Cell::new(None); } pub fn set_error_file_dir(dir: &str) { PANIC_ERROR_OUTPUT.with(|data| { data.set(Some(dir.to_string())); }); } pub fn get_error_file_directory() -> String { let mut file_dir = String::new(); PANIC_ERROR_OUTPUT.with(|data: &Cell<Option<String>>| { file_dir.push_str(&data.get_mut().unwrap()); }); return file_dir; }
原因分析
Cell<T>的get_mut()方法需要接收&mut Cell<T>类型的可变引用,但thread_local!提供的with方法只会传递不可变引用&Cell<T>,因此无法调用get_mut()。另外,Cell更适合存储实现了Copy trait的类型,而Option<String>并不满足Copy,直接用Cell::get()也无法读取内部值。
解决方案
方案1:改用RefCell适配非Copy类型
RefCell是更适合非Copy类型的内部可变性容器,支持在不可变引用下通过借用规则读取内部值:
use std::cell::RefCell; thread_local! { pub static PANIC_ERROR_OUTPUT: RefCell<Option<String>> = RefCell::new(None); } pub fn set_error_file_dir(dir: &str) { PANIC_ERROR_OUTPUT.with(|data| { *data.borrow_mut() = Some(dir.to_string()); }); } pub fn get_error_file_directory() -> String { PANIC_ERROR_OUTPUT.with(|data| { data.borrow().clone().unwrap_or_default() }) }
方案2:使用Cell的replace方法临时获取值
如果坚持使用Cell,可以通过replace方法临时取出内部值,克隆后再放回:
use std::cell::Cell; thread_local! { pub static PANIC_ERROR_OUTPUT: Cell<Option<String>> = Cell::new(None); } pub fn set_error_file_dir(dir: &str) { PANIC_ERROR_OUTPUT.with(|data| { data.set(Some(dir.to_string())); }); } pub fn get_error_file_directory() -> String { PANIC_ERROR_OUTPUT.with(|data| { // 临时取出当前值,用None替换 let current = data.replace(None); // 克隆要返回的字符串 let res = current.clone().unwrap_or_default(); // 将原数值放回Cell data.set(current); res }) }
说明
两种方案中,RefCell的实现更符合常规场景,代码更直观且无需手动处理值的取出和放回,推荐优先使用。
内容的提问来源于stack exchange,提问作者mrtomblue
相关产品推荐
相关产品推荐

