如何将某种通用闭包传递给函数以生成特定值

How to pass some sort of generic closure to a function to generate specific values

这是我的第一个 Rust 项目。我正在研究遗传编程 API,我认为如果碱基对上的基因(在本例中是指令)可以通用(这是一个多表达程序),那会很好。

pub struct Mep<Ins> {
    instructions: Vec<Ins>,
}

我尝试创建一个新函数,该函数采用闭包在向量中生成 Ins

impl<Ins> Mep<Ins> {
    //Generates a new Mep with a particular size and takes a closure to generate random instructions
    pub fn new<F>(total_instructions: usize, random_instruction_generator: F) -> Mep<Ins>
        where F : Fn() -> Ins {
        let mut mep = Mep{instructions: Vec::with_capacity(total_instructions)};
        for _ in 0..total_instructions {
            mep.instructions.push(random_instruction_generator());
        }
        mep
    }
}

这构建得很好,似乎可以工作,但没有实现预期的用例。我打算让用户访问 PRNG 的状态,该 PRNG 在对新功能和其他功能的多次调用中重复使用。就我而言,这是有问题的情况:

...
extern crate rand;
use rand::isaac::Isaac64Rng;
use rand::SeedableRng;
use rand::Rng;
#[test]
fn mep_new() {
    let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
    let len = 80;
    let a: Mep<u32> = Mep::new(len, || rng.next_u32());
}

我创建了一个新的 PRNG,然后希望在闭包中捕获对它的可变引用。 Rust 抱怨这个编译错误:

tests/mep.rs:12:40: 12:43 error: cannot borrow data mutably in a captured outer variable in an `Fn` closure [E0387]
tests/mep.rs:12     let a: Mep<u32> = Mep::new(len, || rng.next_u32());
                                                       ^~~

我发现 this post infers that the closure capture syntax 已移入此新表格。所以我尝试了这个:

#[test]
fn mep_new() {
    let mut rng = Isaac64Rng::from_seed(&[1, 2, 3, 4]);
    let len = 80;
    let a: Mep<u32> = Mep::new(len, |ref rng| rng.next_u32());
}

但是编译器抱怨:

tests/mep.rs:12:51: 12:61 error: the type of this value must be known in this context
tests/mep.rs:12     let a: Mep<u32> = Mep::new(len, |ref rng| rng.next_u32());
                                                                  ^~~~~~~~~~
tests/mep.rs:12:23: 12:31 error: type mismatch: the type `[closure@tests/mep.rs:12:37: 12:61]` implements the trait `core::ops::Fn<([type error],)>`, but the trait `core::ops::Fn<()>` is required (expected (), found tuple) [E0281]
tests/mep.rs:12     let a: Mep<u32> = Mep::new(len, |ref rng| rng.next_u32());
                                      ^~~~~~~~

我应该采取不同的做法吗?迭代器是传递给新函数的更好的东西吗?我宁愿不将通用参数(在本例中为 PRNG)从 new 传递到闭包只是为了解决这个问题。解决这个问题的干净方法是什么?指令将以不同的格式出现,因此需要这样生成。或者,我可以编码特定的指令格式,但我希望看到这种通用方法起作用,这样我就可以对多种指令格式使用相同的代码,从而利用 Rust 的功能。

您需要进行的主要更改是将通用绑定从 Fn 更改为 FnMut。完成后,您还需要使参数 random_instruction_generator 可变:

struct Mep<Ins> {
    instructions: Vec<Ins>,
}

impl<Ins> Mep<Ins> {
    fn new<F>(total_instructions: usize, mut random_instruction_generator: F) -> Mep<Ins>
        where F: FnMut() -> Ins
    {
        let instructions =
            (0..total_instructions)
            .map(|_| random_instruction_generator())
            .collect();

        Mep {
            instructions: instructions,
        }
    }
}

struct FakeRng;
impl FakeRng {
    // https://xkcd.com/221/
    fn next_u32(&mut self) -> u32 { 4 }
}

fn main() {
    let mut rng = FakeRng;
    let a = Mep::new(80, || rng.next_u32());
}

我还更改了您的 where 子句以使用更标准的格式并使用 mapcollect 而不是可变向量。