I am new for rust and I get some move trouble when I want to use multiple thread to do something; and it seems I can’t "real" copy some data;
use std::collections::HashMap;
use std::sync::mpsc;
use std::thread;
pub fn frequency(input: &str, some_chars: Vec<char>){
let all_chars = input.chars();
let mut unique_chars = vec![];
for ci in all_chars {
if ! unique_chars.contains(&ci) {
unique_chars.push(ci);
}
}
let (tx, rx) = mpsc::channel();
for tci in some_chars {
let tx_copy = tx.clone();
thread::spawn(move || {
let mut chars_count= 0 as usize;
let all_chars_copy = all_chars.clone();
for aci in all_chars_copy {
if aci == tci {
chars_count += 1;
}
}
tx_copy.send((tci, chars_count));
});
}
for received in rx {
println!("Got: {:?}", received);
}
}
fn main() {
let a_string = "dsfsdfdsfsdfsdfsdfsdfw4eer34fdefd";
frequency(a_string, vec!['a', 'b', 'c']);
}
The compile error is as below; when I want to move some data on mutiple thread, i should copy some data to "move", but it seems look like failed; shall I get some advice for resolve this problem?
error[E0521]: borrowed data escapes outside of function
--> src\main.rs:18:9
|
6 | pub fn frequency(input: &str, some_chars: Vec<char>){
| ----- - let's call the lifetime of this reference `'1`
| |
| `input` is a reference that is only valid in the function body
...
18 | / thread::spawn(move || {
19 | | let mut chars_count= 0 as usize;
20 | | let all_chars_copy = all_chars.clone();
21 | | for aci in all_chars_copy {
... |
26 | | tx_copy.send((tci, chars_count));
27 | | });
| | ^
| | |
| |__________`input` escapes the function body here
| argument requires that `'1` must outlive `'static`
error[E0382]: use of moved value: `all_chars`
>Solution :
Your code has multiple issues:
- You already move
all_chars
before you even start the first thread here:
for ci in all_chars {
Since it’s cheap you can just create a new one like this:
for ci in input.chars() {
- Your’e trying to clone
all_chars
inside of the closure but at that point you already moved it, so eitherclone
it outside:
thread::spawn({
let all_chars = all_chars.clone();
move || {
let mut chars_count = 0 as usize;
for aci in all_chars {
if aci == tci {
chars_count += 1;
}
}
tx_copy.send((tci, chars_count));
}
});
or just create it from scratch again:
thread::spawn(move || {
let mut chars_count = 0 as usize;
for aci in input.chars() {
if aci == tci {
chars_count += 1;
}
}
tx_copy.send((tci, chars_count));
}
);
- You get bitten by the fact that you’re using
.chars()
borrows the original&str
so it’s referencing local variables, to overcome that you can just usethread::scope
because you read the contents of the threads at the end of the function anyways:
use std::collections::HashMap;
use std::sync::mpsc;
use std::thread;
pub fn frequency(input: &str, some_chars: Vec<char>) {
let mut unique_chars = vec![];
for ci in input.chars() {
if !unique_chars.contains(&ci) {
unique_chars.push(ci);
}
}
let (tx, rx) = mpsc::channel();
thread::scope(|s| {
for tci in some_chars {
let tx_copy = tx.clone();
s.spawn(move || {
let mut chars_count = 0 as usize;
for aci in input.chars() {
if aci == tci {
chars_count += 1;
}
}
tx_copy.send((tci, chars_count));
});
}
});
for received in rx {
println!("Got: {:?}", received);
}
}
- Of course Masklinn is right you don’t need the channel at all.
use std::thread;
pub fn frequency(input: &str, some_chars: Vec<char>) {
let mut unique_chars = vec![];
for ci in input.chars() {
if !unique_chars.contains(&ci) {
unique_chars.push(ci);
}
}
thread::scope(|s| {
let mut ts = Vec::with_capacity(some_chars.len());
for tci in some_chars {
ts.push(s.spawn(move || {
let mut chars_count = 0 as usize;
for aci in input.chars() {
if aci == tci {
chars_count += 1;
}
}
(tci, chars_count)
}));
}
for h in ts {
let (tci, chars_count) = h.join().unwrap();
println!("Got: {:?}", (tci, chars_count));
}
});
}