Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 如何存储和使用使用公共内存区域的闭包?_Rust - Fatal编程技术网

Rust 如何存储和使用使用公共内存区域的闭包?

Rust 如何存储和使用使用公共内存区域的闭包?,rust,Rust,我正在编写一段模拟带有闭包的小型(类型化)玩具语言的Rust代码,但我不确定应该如何将它们存储在enum中,以便在评估闭包时它们仍然能够访问/使用公共堆 我希望程序的数据存储在一个堆上,并且我允许所有的闭包在这个堆中作为参数,以防它需要分配一些东西、检索一个值等。如果闭包代码本身是由Rust动态分配的,我也可以,但是我希望闭包本身的指针位于我的堆结构中 我曾尝试将数据存储为函数指针(如fn(usize,usize,&mut Heap)),以及盒式闭包(如Box usize>),以及带有生存期参数

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

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

我曾尝试将数据存储为函数指针(如
fn(usize,usize,&mut Heap)
),以及盒式闭包(如
Box usize>
),以及带有生存期参数的盒式指针版本(如
Box 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!(),
    };
}
enum Val{
Int(i32),
布尔(布尔),
Lambda(框usize>),
}
结构堆{
mem:Vec,
}
impl堆{
fn alloc(&mut self,v:Val)->使用{
自我记忆推送(v);
self.mem.len()-1
}
fn获取(&self,i:usize)->&Val{
&self.mem[i]
}
}
fn应用(func:usize,arg:usize,heap:&mut heap)->usize{
let closure=匹配heap.get(func){
Val::Lambda(x)=>x,
_=>恐慌!(),
};
闭包(arg,heap)
}
fn main(){
设muth=Heap{mem:vec![]};
//创建闭包
让foo=Val::Lambda(Box::new(| a:usize,mut heap:&mut heap |->usize{
让a_val=匹配heap.get(a){
Val::Int(x)=>*x,
_=>恐慌!(),
};
alloc(Val::Int(a_Val*a_Val))
}));
设f=h.alloc(foo);
//使用闭包
设a=h.alloc(Val::Int(3));
设b=应用(f、a和mut h);
匹配h.get(b){
Val::Int(x)=>println!(“{}”,x),
_=>恐慌!(),
};
}

上述代码应输出9,但存在借用检查器错误:

error[E0596]:不能将`**closure`借用为可变的,因为它位于`&`引用后面
-->src/main.rs:27:5
|
23 | let closure=匹配heap.get(func){
-----帮助:考虑把这个变成一个可变的参考:'MUTSTD::盒装::
...
27 |闭包(arg,heap)
|^^^^`closure`是一个`&`引用,因此它引用的数据不能作为可变数据借用
错误[E0502]:无法将“*heap”作为可变借用,因为它也是作为不可变借用的
-->src/main.rs:27:5
|
23 | let closure=匹配heap.get(func){
|----此处发生不可变借用
...
27 |闭包(arg,heap)
|     -------^^^^^^^^^^^
|     |
|可变借用发生在这里
|不可变借阅稍后由调用使用
警告:变量不需要是可变的
-->src/main.rs:34:47
|
34 |让foo=Val::Lambda(框::new(| a:usize,mut heap:&mut heap |->usize{
|                                               ----^^^^
|                                               |
|帮助:删除此“mut”`
|
=注意:#[警告(未使用的_mut)]默认打开
是否可以克隆我的闭包/枚举以缓解此借用问题?我不确定这是否可行,因为Rust文档中列出了以下限制:

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


您试图执行的操作本质上是内存不安全的。您对向量中的某个对象有一个引用,并可能在该引用未完成时尝试对其进行变异。这可能会使该引用无效。这正是Rust所防止的-引入内存不安全。在堆栈溢出上搜索您得到的错误消息,您将发现关于同一件事的数百个问题。你的直接错误由解决。然后你遇到了Gotcha,谢谢@Shepmaster。我熟悉一般的借阅检查方面,我只是想知道是否有任何方法可以重新编写代码,以更安全地处理传入堆部分。目前,我已通过changin修复了我的代码g my
Val::Lambda
改为使用函数指针,并使所有函数/Lambda/闭包位于顶层(即全局)。您试图执行的操作本质上是内存不安全的。您对向量中的某个对象有引用,并且可能在该引用未完成时尝试对其进行变异。这可能会使该引用无效。这正是Rust所防止的-引入内存不安全。在堆栈溢出上搜索您收到的错误消息,您将发现错误d关于同一件事的数百个问题。你的直接错误由解决。然后你遇到了Gotcha,谢谢@Shepmaster。我熟悉一般的借阅检查方面,我只是在想是否有任何方法可以重新编写我的代码,以更安全地处理传入堆部分。目前,我已通过changi修复了我的代码ng my
Val::Lambda
改为使用函数指针,并使所有函数/Lambda/closures位于顶层(即全局)。