矢量控股可变功能

时间:2018-03-20 22:37:16

标签: rust

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

我遇到的问题是:

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

我最接近的是:

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);
}

1 个答案:

答案 0 :(得分:3)

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

(&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(),它可以自由别名,并且其捕获的环境也可能包含别名引用(当然是不可变的)。