首页 > 解决方案 > 如何存储和使用使用公共内存区域的闭包?

问题描述

我正在编写一段 Rust 代码,它模拟一种带有闭包的小型(类型化)玩具语言,但我不确定我应该如何将它们存储在 an 中,enum以便它们在我评估时仍然能够访问/使用公共堆关闭。

我希望程序的数据存储在一个堆上,并且我允许所有闭包将这个堆作为参数,以防它需要分配一些东西、检索一个值等。如果闭包我没问题代码本身是由 Rust 动态分配的,但我希望指向闭包本身的指针位于我的Heap结构中。

我已经尝试将数据存储为函数指针(如fn(usize, usize, &mut Heap)),以及盒装闭包(如Box<dyn FnMut(usize, &mut Heap) -> usize>),以及带有生命周期参数的盒装指针版本(如Box<dyn FnMut(usize, &mut Heap) -> usize + 'a>),但我似乎总是遇到一些借用问题检查器。

这是我的代码的简化版本:

enum Val {
    Int(i32),
    Bool(bool),
    Lambda(Box<dyn FnMut(usize, &mut Heap) -> usize>),
}

struct Heap {
    mem: Vec<Val>,
}

impl Heap {
    fn alloc(&mut self, v: Val) -> usize {
        self.mem.push(v);
        self.mem.len() - 1
    }

    fn get(&self, i: usize) -> &Val {
        &self.mem[i]
    }
}

fn apply(func: usize, arg: usize, heap: &mut Heap) -> usize {
    let closure = match heap.get(func) {
        Val::Lambda(x) => x,
        _ => panic!(),
    };
    closure(arg, heap)
}

fn main() {
    let mut h = Heap { mem: vec![] };

    // creating a closure
    let foo = Val::Lambda(Box::new(|a: usize, mut heap: &mut Heap| -> usize {
        let a_val = match heap.get(a) {
            Val::Int(x) => *x,
            _ => panic!(),
        };
        heap.alloc(Val::Int(a_val * a_val))
    }));
    let f = h.alloc(foo);

    // using the closure
    let a = h.alloc(Val::Int(3));
    let b = apply(f, a, &mut h);
    match h.get(b) {
        Val::Int(x) => println!("{}", x),
        _ => panic!(),
    };
}

锈操场

上面的代码应该输出 9,但是有一个借用检查器错误:

error[E0596]: cannot borrow `**closure` as mutable, as it is behind a `&` reference
  --> src/main.rs:27:5
   |
23 |     let closure = match heap.get(func) {
   |         ------- help: consider changing this to be a mutable reference: `&mut std::boxed::Box<dyn for<'r> std::ops::FnMut(usize, &'r mut Heap) -> usize>`
...
27 |     closure(arg, heap)
   |     ^^^^^^^ `closure` is a `&` reference, so the data it refers to cannot be borrowed as mutable

error[E0502]: cannot borrow `*heap` as mutable because it is also borrowed as immutable
  --> src/main.rs:27:5
   |
23 |     let closure = match heap.get(func) {
   |                         ---- immutable borrow occurs here
...
27 |     closure(arg, heap)
   |     -------^^^^^^^^^^^
   |     |
   |     mutable borrow occurs here
   |     immutable borrow later used by call

warning: variable does not need to be mutable
  --> src/main.rs:34:47
   |
34 |     let foo = Val::Lambda(Box::new(|a: usize, mut heap: &mut Heap| -> usize {
   |                                               ----^^^^
   |                                               |
   |                                               help: remove this `mut`
   |
   = note: #[warn(unused_mut)] on by default

是否可以克隆我的闭包/枚举以缓解此借用问题?Clone由于Rust 文档列出的限制,我不确定这是否可能:

“闭包类型,如果它们没有从环境中捕获任何值,或者所有这些捕获的值都实现Clone了自己。请注意,共享引用捕获的变量总是实现Clone(即使引用对象没有),而可变引用捕获的变量永远不会实现Clone。”

标签: rust

解决方案


推荐阅读