有没有办法同时不可变地和可变地借用 RefCell?
Is there any way to borrow a RefCell immutably and mutably at the same time?
我有一段代码需要对列表进行操作。此列表包含来自其他来源并需要处理并最终删除的项目。该列表还传递给多个函数,这些函数决定是添加还是删除项目。我创建了一个反映我的问题的示例代码:
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 文档,这是不允许的:许多不可变借用或单个可变借用。有什么办法可以解决这个问题吗?
我不知道你实际上想要实现什么,因为你没有提供 minimal reproducible example,但我认为你只是混淆了 list
和 [=12] 的借用=] 在你的数据结构中,这首先让你感到困惑。
尽管如此,以下代码(您可以在 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
中删除项目,所以我能够使用 pop
或remove
方法(取决于您希望从 list
中获取项目的顺序)。这意味着我不必为循环范围借用 Vec
(如果你要遍历它,你会这样做)。
还有其他方法可以根据某些谓词删除元素。例如:.
实际回答你原来的问题:没有办法安全地同时拥有不可变和可变借用。这是 Rust 的核心原则之一,它使内存安全。想一想,如果在同一时间,在引擎盖下,数据实际上可以改变,那么不变性是一种什么样的保证?
我有一段代码需要对列表进行操作。此列表包含来自其他来源并需要处理并最终删除的项目。该列表还传递给多个函数,这些函数决定是添加还是删除项目。我创建了一个反映我的问题的示例代码:
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 文档,这是不允许的:许多不可变借用或单个可变借用。有什么办法可以解决这个问题吗?
我不知道你实际上想要实现什么,因为你没有提供 minimal reproducible example,但我认为你只是混淆了 list
和 [=12] 的借用=] 在你的数据结构中,这首先让你感到困惑。
尽管如此,以下代码(您可以在 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
中删除项目,所以我能够使用pop
或remove
方法(取决于您希望从list
中获取项目的顺序)。这意味着我不必为循环范围借用Vec
(如果你要遍历它,你会这样做)。
还有其他方法可以根据某些谓词删除元素。例如:
实际回答你原来的问题:没有办法安全地同时拥有不可变和可变借用。这是 Rust 的核心原则之一,它使内存安全。想一想,如果在同一时间,在引擎盖下,数据实际上可以改变,那么不变性是一种什么样的保证?