我的代码中的非法移动在哪里?
Where's the illegal move in my code?
我在移动不应该移动的 (a) 个值时遇到错误,但错误并没有说明我不小心移动了什么,我错过了它当我只看代码时。
错误:
-*- 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);
}
}
因为 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
被释放之前加入你的守卫。
我在移动不应该移动的 (a) 个值时遇到错误,但错误并没有说明我不小心移动了什么,我错过了它当我只看代码时。
错误:
-*- 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);
}
}
因为 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
被释放之前加入你的守卫。