rust - 如何存储和使用使用公共内存区域的闭包?
问题描述
我正在编写一段 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
。”
解决方案
推荐阅读
- python - 如何在 VScode 中添加 python 包?
- spring - Lombok:生成 2 个具有指定字段的构造函数
- javascript - 反应传单标记坏了
- amazon-web-services - 同一个安全组中默认打开哪些端口与其中的实例进行通信?
- python - 远程:-----> 应用程序与 buildpack 不兼容:托管不和谐机器人时出现 heroku 错误
- flutter - 使用带有 List 的 add 函数与创建新方法在列表中添加数据
- python - 如何用 python 操作这个国际象棋符号?
- pypdf2 - Pdf Reader 编辑器不会将对象添加到主根对象
- javascript - 收集的元数据包含将在运行时报告的错误:Reference to a non-exported function
- rust-polars - 使用 Rust Polars,有没有一种很好的方法来替换像 fill_null 这样的系列中的指定值?