如何返回对当前函数拥有的值的可变引用

问题描述 投票:0回答:1

这是我的结构,我需要一个

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
}
rust borrow-checker ownership mutable-reference
1个回答
0
投票

你不能;根本没有办法返回对包装在

&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);
}
© www.soinside.com 2019 - 2024. All rights reserved.