这是我的结构,我需要一个
get_mut
函数,它返回对以下任一者拥有的值的可变引用
ctx.scope
或 ctx.parent.scope
递归
pub type RuntimeContext<'c> = Rc<RefCell<Context<'c>>>;
pub struct Context<'c>
{
pub parent: Option<RuntimeContext<'c>>,
pub scope: HashMap<String, Value>,
pub eval: Value,
}
这是我尝试过的,但正如预期的那样,借用检查器抱怨
cannot return reference to temporary value returns a reference to data owned by the current function
,还有什么其他方法可以实现此目的?
(保证父ctx勾画出当前ctx)
impl<'c> Context<'c> {
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
if let Some(v) = self.scope.get_mut(key) {
Some(v)
} else if let Some(parent) = &mut self.parent {
parent.borrow_mut().get_mut(key) // here it breaks
} else {
None
}
}
// ... some other methods
}
你不能;根本没有办法返回对包装在
&mut
中的对象成员的 Rc<RefCel<>>
引用。 RefCell
需要一个守卫对象来跟踪该对象当前是否被借用。然而,&mut
引用不会做这样的事情,使得 RefCell
无法知道 &mut
引用在其保护解除后是否存在。这发生在函数末尾。
通常,可以返回仍包含防护对象的内容,但这当然与您想要从
scope
成员返回引用的其他返回路径不兼容。
我可以想到两种方法来实现这一目标:
枚举的返回值很难正确获取,并且由于变量的多层深度嵌套,会变得非常复杂。
所以我个人会选择第二种选择。
这可能是这样的:
use std::{cell::RefCell, collections::HashMap, rc::Rc};
#[derive(Debug)]
pub struct Value;
pub type RuntimeContext<'c> = Rc<RefCell<Context<'c>>>;
pub struct Context<'c> {
pub parent: Option<RuntimeContext<'c>>,
pub scope: HashMap<String, Value>,
pub eval: Value,
}
impl<'c> Context<'c> {
pub fn get_mut<R>(&mut self, key: &str, f: impl FnOnce(Option<&Value>) -> R) -> R {
if let Some(v) = self.scope.get_mut(key) {
f(Some(v))
} else if let Some(parent) = &mut self.parent {
parent.borrow_mut().get_mut(key, f) // here it breaks
} else {
f(None)
}
}
// ... some other methods
}
// Example on how to use this
pub fn do_something(context: &mut Context) {
let y = context.get_mut("foobarkey", |value| {
println!("Got value: {:?}", value);
let computed_result = 42;
computed_result
});
println!("Result: {}", y);
}