我有一段代码需要对列表进行操作。此列表包含来自其他来源的项目,需要对其进行处理并最终将其删除。该列表还传递给决定添加还是删除项目的多个功能。我创建了一个示例代码来反映我的问题:
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);
}
}
运行时出现紧急情况:
thread 'main' panicked at 'already borrowed: BorrowMutError', src/libcore/result.rs:997:5
我认为我理解问题所在:我有两次不可变的借贷,然后第三次是可变的。根据Rust的文档,这是不允许的:很多不可变的借项或一个可变的借项。有什么办法可以解决这个问题?
答案 0 :(得分:1)
我不知道您由于未能提供minimal reproducible example而实际上要达到什么目的,但是我认为您只是混用了list
和item
的借用在您的数据结构中,这首先使您感到困惑。
尽管如此,以下代码(您可以在playground中运行)可以实现上面所述的功能。
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();
}
我在这里使用了两个技巧。
我只借了一次list
,而借来的却是可变的,这使我可以从中添加和删除项目。
因为您的描述说您仍然想从list
删除项目,所以我能够使用Vec
或{{1}遍历pop
}方法(取决于您希望从remove
获取项目的顺序)。这意味着我不必借用list
作为循环的范围(如果您要遍历循环,则可以这样做)。
还有其他方法可基于某些谓词删除元素。例如:Removing elements from a Vec based on some condition。
要真正回答您的原始问题:无法安全地同时拥有一个不变的和可变的借贷。这是Rust使内存安全的核心原则之一。想想看,如果同时在后台实际改变数据,不变性将是一种什么样的保证?