rust - 持有可变函数的向量

标签 rust

我想要一个带有函数的向量。然后我想迭代这个向量并一个一个地执行函数。这些函数会改变外部状态。此外,我希望能够在向量中放置两次相同的函数。

我遇到的问题是:

  • 我无法取消引用并执行向量中的函数,
  • 将相同的函数添加到 vector 两次都失败了,这是可以理解的错误,我不能有两个可变引用。

我得到的最接近的是:

fn main() {
    let mut c = 0;
    {
        let mut f = ||{c += 1};
        let mut v: Vec<&mut FnMut()> = vec![];
        v.push(&mut f);

        // How to execute the stored function? The following complains about
        // an immutable reference:
        //    assignment into an immutable reference
        // (v[0])();

        // How to store the same function twice? The following will fail with:
        //     cannot borrow `f` as mutable more than once at a time
        // v.push(&mut f);
    }
    println!("c {}", c);
}

最佳答案

对于第一个问题,我真的不知道为什么这里没有发生可变的取消引用(在我看来,它应该),但有一个简单的解决方法:只需执行取消引用然后手动引用:

(&mut *v[0])();

不过,您的第二个问题更复杂。没有简单的解决方案,因为您尝试做的事情违反了 Rust 别名保证,并且由于您没有描述它的目的,所以我无法正确建议替代方案。但是,一般来说,您可以通过使用 Cell/RefCellMutex 切换到运行时借用检查来克服此错误(后者是当您需要并发访问)。使用 Cell(适用于原语):

use std::cell::Cell;

fn main() {
    let c = Cell::new(0);
    {
        let f = || { c.set(c.get() + 1); };
        let mut v: Vec<&Fn()> = vec![];
        v.push(&f);
        v.push(&f);

        v[0]();
        v[1]();
    }
    println!("c {}", c.get());
}

使用 RefCell(适用于更复杂的类型):

use std::cell::RefCell;

fn main() {
    let c = RefCell::new(0);
    {
        let f = || { *c.borrow_mut() += 1; };
        let mut v: Vec<&Fn()> = vec![];
        v.push(&f);
        v.push(&f);

        v[0]();
        v[1]();
    }
    println!("c {}", *c.borrow());
}

如您所见,现在您有 &Fn() 而不是 &mut FnMut(),它可以自由别名,并且其捕获的环境也可能包含别名引用(当然是不可变的)。

关于rust - 持有可变函数的向量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49395257/

相关文章:

rust - 如何从结果中获取值?

rust - Rust函数语法问题,示例出现在nom中

asynchronous - 为什么在 crossbeam_channel::select 旁边调用时 tokio::spawn 有延迟?

async-await - 我如何通过特征及其相关生命周期加入嵌套的 BoxFutures?

postgresql - 使用 Rust Diesel 插入记录时处理 ID 的最佳方法是什么

rust - 是否需要在使用时导入特征?

vector - 一般如何将数据移出可索引集合?

rust - Rust 中的进程退出

macros - 如何将空白/空参数传递给 Rust 中的宏?

rust - 重新打开AboutDialog将显示一个空白对话框