Is there any way to borrow a RefCell immutably and mutably at the same time?
我有一段代码需要对列表进行操作。此列表包含来自其他来源的项目,需要对其进行处理并最终将其删除。该列表还传递给决定添加还是删除项目的多个功能。我创建了一个示例代码来反映我的问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | use std::{cell::RefCell, rc::Rc}; pub fn foo() { let list: Rc<RefCell<Vec<Rc<RefCell<String>>>>> = Rc::new(RefCell::new(Vec::new())); list.borrow_mut() .push(Rc::new(RefCell::new(String::from("ABC")))); while list.borrow().len() > 0 { let list_ref = list.borrow(); let first_item = list_ref[0].borrow_mut(); //item processing, needed as mutable list.borrow_mut().remove(0); } } |
运行时出现紧急情况:
1 | thread 'main' panicked at 'already borrowed: BorrowMutError', src/libcore/result.rs:997:5 |
我想我明白问题所在:我有两次不可变的借贷,而第三次是可变的。根据Rust文档,这是不允许的:很多不可变的借用或一个可变的借用。有什么办法可以解决这个问题?
我不知道您实际上试图实现什么,因为您未能提供最小的可复制示例,但是我认为您只是在数据结构中混用了
尽管如此,以下代码(您可以在操场上运行)可以完成上述操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | use std::{cell::RefCell, rc::Rc}; pub fn foo() { let list = Rc::new(RefCell::new(Vec::new())); let mut list = list.borrow_mut(); let item = Rc::new(RefCell::new(String::from("ABC"))); list.push(item); println!("list: {:?}", list); while let Some(item) = list.pop() { println!("item: {:?}", item); item.borrow_mut().push_str("DEF"); println!("item: {:?}", item); } println!("list: {:?}", list); } fn main() { foo(); } |
我在这里使用了两个技巧。
我只借过一次
因为您的描述说您仍然想从
还有其他方法可基于某些谓词删除元素。例如:根据某些条件从Vec中删除元素。
要真正回答您的原始问题:无法安全地同时拥有一个不变的和可变的借贷。这是Rust使内存安全的核心原则之一。想一想,如果同时在后台实际更改数据,不变性将是一种什么样的保证?