2015-08-28 2 views
2

Я получаю ошибку, что я перемещаю (а) значения, которых я не должен быть, но ошибка не дает понять, что я случайно перемещаю, и я пропускаю это, когда я просто посмотрите на код.Где незаконный ход в моем коде?

Ошибка:

-*- mode: compilation; default-directory: "~/Developer/Rust/optimal_subset_finder/src/" -*- 
Compilation started at Thu Aug 27 21:53:26 

cargo build 
    Compiling optimal_subset_finder v0.1.1 (file:///Users/camdennarzt/Developer/Rust/optimal_subset_finder) 
main.rs:66:23: 98:10 error: cannot move out of captured outer variable in an `FnMut` closure 
main.rs:66   thread::spawn(move || { 
main.rs:67    let mut best_set : Vec<String> = Vec::new(); 
main.rs:68    let mut best_count = 0; 
main.rs:69    let mut rng = thread_rng(); 
main.rs:70    let mut indices = Vec::new(); 
main.rs:71    let limit = attempts.clone()/num_cpus::get(); 
      ... 
note: in expansion of closure expansion 
main.rs:66:23: 98:10 note: expansion site 
note: in expansion of closure expansion 
main.rs:63:57: 99:6 note: expansion site 
main.rs:66:23: 98:10 error: cannot move out of captured outer variable in an `FnMut` closure 
main.rs:66   thread::spawn(move || { 
main.rs:67    let mut best_set : Vec<String> = Vec::new(); 
main.rs:68    let mut best_count = 0; 
main.rs:69    let mut rng = thread_rng(); 
main.rs:70    let mut indices = Vec::new(); 
main.rs:71    let limit = attempts.clone()/num_cpus::get(); 
      ... 
note: in expansion of closure expansion 
main.rs:66:23: 98:10 note: expansion site 
note: in expansion of closure expansion 
main.rs:63:57: 99:6 note: expansion site 
error: aborting due to 2 previous errors 
Could not compile `optimal_subset_finder`. 

To learn more, run the command again with --verbose. 

Compilation exited abnormally with code 101 at Thu Aug 27 21:53:27 

код:

extern crate rand; 
extern crate csv; 
extern crate num_cpus; 
extern crate rustc_serialize; 
extern crate docopt; 

use std::fs::File; 
use csv::Reader; 
use rand::{thread_rng, sample}; 
use std::thread; 
use std::io::{self, Write}; 
use std::sync::{Arc, Mutex}; 
use docopt::Docopt; 
use std::collections::HashSet; 

fn as_bool(rdr:&mut Reader<File>)->Vec<Vec<bool>>{ 
    rdr.records().map(|r|{ 
     r.unwrap().iter().skip(1).map(|r|{ 
      r == "TRUE" 
     }).collect() 
    }).collect() 
} 

fn as_strings(rdr:&mut Reader<File>)->Vec<String>{ 
    rdr.records().map(|r|{ 
     r.unwrap()[0].clone() 
    }).collect() 
} 

fn met_n_in_common(n:usize,csv:&Vec<Vec<bool>>)->bool{ 
    csv.iter().all(|r|r[n]) 
} 

fn mets_in_common(csv:&Vec<Vec<bool>>)->usize { 
    (0..csv[0].len()).filter(|i| met_n_in_common(*i,csv)).count() 
} 

const USAGE: &'static str = " 
Usage: 
    ./optimal_subset_finder PATH ATTEMPTS 
"; 

#[derive(Debug, RustcDecodable)] 
struct Args { 
    arg_PATH: String, 
    arg_ATTEMPTS: usize, 
} 

fn main() { 
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit()); 
    let attempts = args.arg_ATTEMPTS.clone(); 

    let mut csv = csv::Reader::from_file(args.arg_PATH.clone()).unwrap(); 
    let data = as_bool(&mut csv); 
    csv.seek(0); 
    let files = as_strings(&mut csv); 

    let tried_indices = Arc::new(Mutex::new(HashSet::new())); 
    let results = Arc::new(Mutex::new(Vec::new())); 

    let mut threads : Vec<_> = (0..num_cpus::get()).map(|i|{ 
     let tried_indices = tried_indices.clone(); 
     let results = results.clone(); 
     thread::spawn(move || { 
      let mut best_set : Vec<String> = Vec::new(); 
      let mut best_count = 0; 
      let mut rng = thread_rng(); 
      let mut indices = Vec::new(); 
      let limit = attempts.clone()/num_cpus::get(); 

      for _ in (0..limit) { 
       { 
        let mut tried_indices = tried_indices.lock().unwrap(); 
        while { 
         let count = *sample(&mut rng, 13..83, 1).first().unwrap(); 
         indices = sample(&mut rng, 0..83, count); 
         tried_indices.contains(&indices) 
        }{} 
        tried_indices.insert(indices.to_owned()); 
       }; 
       let current_set:Vec<_> = { 
        indices.iter().map(|i|{ 
         files[*i].clone() 
        }).collect() 
       }; 
       let current_count = mets_in_common(&data); 
       if (current_count > best_count){ 
        best_count = current_count; 
        best_set = current_set; 
       } 
      } 
      { 
       let mut results = results.lock().unwrap(); 
       results.push((best_count,best_set)); 
      } 
     }) 
    }).collect(); 
    for t in threads.into_iter() { 
     t.join(); 
    } 
    { 
     let mut results = results.lock().unwrap().to_owned(); 
     let first = results.pop().unwrap(); 
     let (count,set) = results.into_iter().fold(first,|a,r| if(a.0 < r.0){r}else{a}); 
     println!("results {:?} {:?}",count,set); 
    } 
} 
+0

Попробуйте добавить формулировки формы 'let x = & x' (или' let x = & mut x', если вам нужна изменчивость) перед вызовом 'thread :: spawn', где' x' - это переменная, используемая в закрытие было передано 'thread :: spawn'. При этом закрытие будет захватывать ссылки, а не значения напрямую. –

+0

Тогда компилятор не знает, что ссылки живут достаточно долго, потому что область действия на карте заканчивается до того, как поток будет выполнен. –

ответ

1

Из-за того, как move замыкания внутри другого закрытия, а не на внешнем уровне (например, если вы имели for цикл толкающий к вектору), сообщение об ошибке действительно не очень хорошо, но если вы отбрасываете ключевое слово move, вы можете получить несколько более эффективные сообщения об ошибках:

<anon>:42:23: 71:10 error: closure may outlive the current function, but it borrows `tried_indices`, which is owned by the current function [E0373] 
<anon>:42   thread::spawn(|| { 
<anon>:43    let mut best_set : Vec<String> = Vec::new(); 
<anon>:44    let mut best_count = 0; 
<anon>:45    let mut indices: Vec<usize> = Vec::new(); 
<anon>:46    let limit = 1; 
<anon>:47 
      ... 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
<anon>:50:45: 50:58 note: `tried_indices` is borrowed here 
<anon>:50      let mut tried_indices = tried_indices.lock().unwrap(); 
                 ^~~~~~~~~~~~~ 
note: in expansion of for loop expansion 
<anon>:48:13: 66:14 note: expansion site 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
<anon>:42:23: 71:10 help: to force the closure to take ownership of `tried_indices` (and any other referenced variables), use the `move` keyword, as shown: 
<anon>:   thread::spawn(move || { 
<anon>:    let mut best_set : Vec<String> = Vec::new(); 
<anon>:    let mut best_count = 0; 
<anon>:    let mut indices: Vec<usize> = Vec::new(); 
<anon>:    let limit = 1; 
<anon>: 
      ... 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
<anon>:42:23: 71:10 error: closure may outlive the current function, but it borrows `**files`, which is owned by the current function [E0373] 
<anon>:42   thread::spawn(|| { 
<anon>:43    let mut best_set : Vec<String> = Vec::new(); 
<anon>:44    let mut best_count = 0; 
<anon>:45    let mut indices: Vec<usize> = Vec::new(); 
<anon>:46    let limit = 1; 
<anon>:47 
      ... 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
<anon>:58:25: 58:30 note: `**files` is borrowed here 
<anon>:58       files[*i].clone() 
            ^~~~~ 
note: in expansion of closure expansion 
<anon>:57:40: 59:22 note: expansion site 
note: in expansion of for loop expansion 
<anon>:48:13: 66:14 note: expansion site 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
<anon>:42:23: 71:10 help: to force the closure to take ownership of `**files` (and any other referenced variables), use the `move` keyword, as shown: 
<anon>:   thread::spawn(move || { 
<anon>:    let mut best_set : Vec<String> = Vec::new(); 
<anon>:    let mut best_count = 0; 
<anon>:    let mut indices: Vec<usize> = Vec::new(); 
<anon>:    let limit = 1; 
<anon>: 
      ... 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
<anon>:42:23: 71:10 error: closure may outlive the current function, but it borrows `**data`, which is owned by the current function [E0373] 
<anon>:42   thread::spawn(|| { 
<anon>:43    let mut best_set : Vec<String> = Vec::new(); 
<anon>:44    let mut best_count = 0; 
<anon>:45    let mut indices: Vec<usize> = Vec::new(); 
<anon>:46    let limit = 1; 
<anon>:47 
      ... 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
<anon>:61:53: 61:57 note: `**data` is borrowed here 
<anon>:61     let current_count = mets_in_common(&data); 
                   ^~~~ 
note: in expansion of for loop expansion 
<anon>:48:13: 66:14 note: expansion site 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
<anon>:42:23: 71:10 help: to force the closure to take ownership of `**data` (and any other referenced variables), use the `move` keyword, as shown: 
<anon>:   thread::spawn(move || { 
<anon>:    let mut best_set : Vec<String> = Vec::new(); 
<anon>:    let mut best_count = 0; 
<anon>:    let mut indices: Vec<usize> = Vec::new(); 
<anon>:    let limit = 1; 
<anon>: 
      ... 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
<anon>:42:23: 71:10 error: closure may outlive the current function, but it borrows `results`, which is owned by the current function [E0373] 
<anon>:42   thread::spawn(|| { 
<anon>:43    let mut best_set : Vec<String> = Vec::new(); 
<anon>:44    let mut best_count = 0; 
<anon>:45    let mut indices: Vec<usize> = Vec::new(); 
<anon>:46    let limit = 1; 
<anon>:47 
      ... 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
<anon>:68:35: 68:42 note: `results` is borrowed here 
<anon>:68     let mut results = results.lock().unwrap(); 
              ^~~~~~~ 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
<anon>:42:23: 71:10 help: to force the closure to take ownership of `results` (and any other referenced variables), use the `move` keyword, as shown: 
<anon>:   thread::spawn(move || { 
<anon>:    let mut best_set : Vec<String> = Vec::new(); 
<anon>:    let mut best_count = 0; 
<anon>:    let mut indices: Vec<usize> = Vec::new(); 
<anon>:    let limit = 1; 
<anon>: 
      ... 
note: in expansion of closure expansion 
<anon>:42:23: 71:10 note: expansion site 
note: in expansion of closure expansion 
<anon>:39:43: 72:6 note: expansion site 
error: aborting due to 4 previous errors 

Это указывает на то, что есть четыре переменных, которые захватываются, и указывает, что два из них вызывают проблемы, когда он хочет захватить по значению; это files и data.

Оба являются векторами, которые могут быть доступны только из одного потока. И thread::spawn требует, чтобы у него были все данные; средство проверки займа не может рассуждать о том, что ваш защитник соединения соединен до того, как освобождены data и files.

+0

Должен ли я переключаться на облачные потоки или есть тип данных, который я могу использовать, чтобы я мог делиться доступом только для чтения к потокам без блокировки? –

+1

Дуга - это то, что вы ищете. – llogiq

Смежные вопросы