如何将某种通用闭包传递给函数以生成特定值
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
子句以使用更标准的格式并使用 map
和 collect
而不是可变向量。
这是我的第一个 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
子句以使用更标准的格式并使用 map
和 collect
而不是可变向量。