如何将引用返回到 Rc<RefCell<>> 函数参数?



这是一个最小的可重现错误,取自我正在编写的解释器。据我了解,我应该能够返回对 RefCell 中结构字段的引用,因为 RefCell 具有足够的生存期。但是,编译器告诉我我无法返回对当前函数拥有的值的引用,坦率地说,这让我感到困惑。

use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Debug)]
enum Value {
Number,
String,
}
struct Object {
pub properties: HashMap<String, Value>,
}
impl Object {
pub fn get_property(&mut self, name: &str) -> Option<&mut Value> {
self.properties.get_mut(name)
}
}
fn get_property(global_object_rcc: Rc<RefCell<Object>>, name: &str) -> Option<&mut Value> {
// Rust cannot verify that this Rc isn't the last Rc that just got moved into this function?
global_object_rcc.borrow_mut().get_property(name)
}
fn main() {
// Construct global object
let mut global_object = Object {
properties: HashMap::new(),
};
// Give it a property
global_object
.properties
.insert("Test".to_owned(), Value::Number);
// Put it in a Rc<RefCell> (rcc) for sharing
let global_object_rcc = Rc::new(RefCell::new(global_object));
// Get a reference to its property, should be valid because the reference only needs to live
// as long as the global_object
let property = get_property(global_object_rcc, "Test");
dbg!(&property);
}

这是我收到的错误消息:

error[E0515]: cannot return value referencing temporary value
--> srcmain.rs:23:5
|
23 |     global_object_rcc.borrow_mut().get_property(name)
|     ------------------------------^^^^^^^^^^^^^^^^^^^
|     |
|     returns a value referencing data owned by the current function
|     temporary value created here

这行不通。RefCell上的borrow_mut()返回一个RefMut,它管理可变借用并确保在它活着时没有其他借用。然后调用get_property借用RefMut(通过 deref 和&mut self隐式)并返回一个与方法的接收器(&mut self)具有相同生存期的引用 (&mut Value)。因此,&mut Value的寿命取决于活着的RefMut;但是当get_property返回时,它会被销毁,使引用无效。

RefCell(就此而言的任何Cell)的全部意义在于借款无法"逃脱"。您可以尝试使用&mut Value调用的闭包;或者,您可以将RefMut退还给调用方,但缺点是您的类型不能排除调用方保留它,从而防止将来借用。

调用.borrow_mut()时,会返回一个临时借用的引用,然后可以取消引用以改变内部数据。 您获得的引用将从borrow_mut()返回到.get_property(name)返回,这不足以让引用在函数结束时存活。

这与Rc<RefCell<Object>>的生命周期不同,后者实际上被移动到被调用的函数中,一旦函数返回就会被删除(但是 Rc 只会递减 refcount,并且只有在 refcount 为 0 时才删除内部数据)。 引用的生存期不能链接到Rc<>内内部数据的生存期,因为根据引用计数,该生存期直到运行时才知道。

如果.borrow_mut()调用发生在fn get_property()之外,并且你传入了一个&mut Objectfn get_property(),这样它返回Option<&mut Value,那么你可以使用一个生命周期变量将输入引用生存期链接到输出引用生存期,这将绕过编译器错误:

fn get_property<'a>(global_object_rcc: &'a mut Object, name: &str) -> Option<&'a mut Value> { ... }

但从此示例的外观来看,这可能不是您想要执行的操作。

最好是根据需要更改数据的函数,这样您只让借用的引用由.borrow_mut()返回尽可能短的时间(仅足够长的时间以更改函数中的数据,并在不再需要引用时返回)。 长时间坚持.borrow_mut()参考会引起恐慌!() 如果您尝试多次借用参考资料。

最新更新