Rust结构体字段使用引用有什么限制?设为None后为何无法修改原对象
问题根源
Rust的生命周期是编译期静态检查的规则,你给Foo结构体标注的生命周期'a,约束的是整个foo实例的存活周期和被借用的string的生命周期绑定,和你运行时把ref_data设为None没有关系。
编译器不会判断运行时ref_data的具体值,只要foo实例还没销毁,就会认为string的借用一直存在。而你直接使用独立的Option<&str>变量时,没有固定的生命周期绑定,编译器可以识别到你把它设为None后借用就已经结束,所以不会报错。
解决方案
方案1:用作用域拆分借用周期
如果可以接受拆分foo的使用阶段,用代码块限制第一个借用的生命周期,等foo实例销毁后再修改string,之后再重建foo即可:
struct Foo<'a> { pub ref_data: Option<&'a str>, } fn main() { let mut string = "mutable string".to_string(); { let mut foo = Foo{ref_data: Some(&string)}; // 这里执行需要用到foo的逻辑 foo.ref_data = None; } // 块内的foo已经销毁,借用已经释放,可以修改string string = "mutated string".to_string(); // 重新创建foo绑定新的引用 let mut foo = Foo{ref_data: Some(&string)}; }
方案2:使用运行时借用检查的智能指针
如果要保留同一个foo实例,就放弃静态生命周期的引用,改用Rc<RefCell<T>>(单线程场景)或者Arc<RwLock<T>>(多线程场景),把借用检查放到运行时执行:
use std::cell::RefCell; use std::rc::Rc; struct Foo { // 不再需要生命周期标注 pub ref_data: Option<Rc<RefCell<String>>>, } fn main() { let string = Rc::new(RefCell::new("mutable string".to_string())); let mut foo = Foo{ref_data: Some(Rc::clone(&string))}; // 修改前不需要设为None,直接通过智能指针修改即可 *string.borrow_mut() = "mutated string".to_string(); // 后续照常使用foo的引用 println!("{}", foo.ref_data.as_ref().unwrap().borrow()); }
方案3:用索引代替引用
如果被引用的对象存储在集合(比如Vec、HashMap)中,可以让结构体存储索引值而非直接引用,完全规避生命周期问题,修改原对象时也不会有借用冲突。
内容的提问来源于stack exchange,提问作者hochej
相关产品推荐
相关产品推荐

