2015-10-14 43 views
2

這是我的第一個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,然後希望捕獲在封閉一個可變引用。拉斯特抱怨這個編譯錯誤:

我發現this post推斷出這一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 `[[email protected]/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傳遞給closure來解決這個問題。什麼是解決這個問題的乾淨方法?說明將以不同的格式出現,因此需要按照這種格式生成。另外,我可以編碼一種特定的指令格式,但我希望看到這種通用方法的工作原理,因此我可以使用相同的代碼來處理多種指令格式,並利用Rust的功能。

+0

請注意,您的兩個鏈接在Rust方面都非常陳舊。 Rust 1.0 2015-05-15發佈,1.0 beta版之前的信息通常是可疑的。 – Shepmaster

回答

2

您需要進行的主要更改是將您的通用範圍從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而不是一個可變的載體。

+0

非常感謝。我仍然從C++進行適應,因此也很高興看到Rust在這種情況下如何使用迭代器。這是完全不同的,所以我從不會想到以這種方式返回Mep! Rust的複製潛力非常強大。我還會在Rust中尋找更多的標準格式。 – vadix

+1

*在這種情況下如何使用迭代器* - 我從具有良好迭代器的語言中學到的一件事情是,很少需要可變容器。此外,在許多情況下,您只需要一個'for'循環作爲引起副作用的地方。 *更多標準格式的做法* - 最終,[rustfmt](https://github.com/nrc/rustfmt)將是獲得一致格式的簡單解決方案。^_ ^ – Shepmaster

相關問題