2015-11-03 26 views
0

我想在多個線程中改變一個可變的變量。我知道這不是線程安全的,但我想知道Rust編譯器將如何處理它。所以我用了一系列的map功能產卵子線程:在多個線程中改變一個共享的可變變量

use std::thread; 

fn break_law(value: &mut i32) { 
    *value += 20; 
} 

fn main() { 
    let mut x = 10; 

    let handles = (0..10).map(|| { 
     thread::spawn(move || { 
     break_law(&mut x); 
     println!("{:?}", x); 
     }) 
    }).collect(); 

    for h in handles { 
     h.join().unwrap(); 
    } 
} 

但我得到一個錯誤:

break_law1.rs:10:24: 15:4 error: type mismatch: the type `[[email protected]_law1.rs 
:10:28: 15:3 x:_]` implements the trait `core::ops::FnMut<()>`, but the trait `c 
ore::ops::FnMut<(_,)>` is required (expected tuple, found()) [E0281] 
break_law1.rs:10  let handles = (0..10).map(|| { 
break_law1.rs:11    thread::spawn(move || { 
break_law1.rs:12      break_law(&mut x); 
break_law1.rs:13      println!("{:?}", x); 
break_law1.rs:14    }) 
break_law1.rs:15  }).collect(); 
break_law1.rs:10:24: 15:4 help: run `rustc --explain E0281` to see a detailed ex 
planation 
break_law1.rs:10:24: 15:4 error: type mismatch: the type `[[email protected]_law1.rs 
:10:28: 15:3 x:_]` implements the trait `core::ops::FnOnce<()>`, but the trait ` 
core::ops::FnOnce<(_,)>` is required (expected tuple, found()) [E0281] 
break_law1.rs:10  let handles = (0..10).map(|| { 
break_law1.rs:11    thread::spawn(move || { 
break_law1.rs:12      break_law(&mut x); 
break_law1.rs:13      println!("{:?}", x); 
break_law1.rs:14    }) 
break_law1.rs:15  }).collect(); 
break_law1.rs:10:24: 15:4 help: run `rustc --explain E0281` to see a detailed ex 
planation 
break_law1.rs:15:5: 15:14 error: type mismatch: the type `[[email protected]_law1.rs 
:10:28: 15:3 x:_]` implements the trait `core::ops::FnMut<()>`, but the trait `c 
ore::ops::FnMut<(_,)>` is required (expected tuple, found()) [E0281] 
break_law1.rs:15  }).collect(); 
          ^~~~~~~~~ 
break_law1.rs:15:5: 15:14 help: run `rustc --explain E0281` to see a detailed ex 
planation 
break_law1.rs:18:6: 18:14 error: the type of this value must be known in this co 
ntext 
break_law1.rs:18   h.join().unwrap(); 
          ^~~~~~~~ 
break_law1.rs:17:2: 19:3 note: in this expansion of for loop expansion 
error: aborting due to 4 previous errors 

根據上述信息,我得到這個範圍內的map函數的定義是這樣的:

// Creates a new iterator that will apply the specified function to each 
// element returned by the first, yielding the mapped element instead. 
fn map<B, F>(self, f: F) -> Map<Self, F> 
    where F: FnMut(Self::Item) -> B 

這看起來很奇怪,但我該如何糾正?爲什麼?

回答

0

map類型簽名稱它採用類型參數(F),其是獲取傳遞一個參數即類型的迭代器的產率((Self::Item)),並返回一個B-> B)的封閉件(FnMut)。你缺少的是參數:它需要是.map(|x| { ... })而不是.map(|| { ... })

如果你不關心參數的值,你可以寫.map(|_| { ... }),使用_模式忽略它,或.map(|_i| { ... }),其中超前_是約定來表示變量是指不使用(它使編譯器關於未使用變量的正常警告無效)。

FWIW,該錯誤信息是有點長,但它確實有這個信息:

type mismatch: the type `[[email protected]_law1.rs:10:28: 15:3 x:_]` implement 
    the trait `core::ops::FnMut<()>`, 
but the trait `core::ops::FnMut<(_,)>` is required 

我已經把換行來突出差異:編譯器抱怨說,你傳遞給關閉map不需要參數(FnMut<()>),當它實際上需要一個參數時(FnMut<(_,)>_表示尚未獲得足夠信息的類型參數以完全推斷出來)。

+0

它確實work.Thanks。這個函數簽名與C++完全不同。順便說一句,就像@swizard所說的那樣,每個線程都會收到一個變量x的副本,所以外部作用域中的x不會發生變異。 –

0

順便說一句,即使在修復上面顯示的參數編號問題之後,您也不會得到您想要的行爲。該代碼將成功編譯,因爲每個線程將收到變量x副本,只要Rust中的整型類型實現Copy特徵。

我想正確的榜樣應該是這樣的:

fn break_law(value: &mut i32) { 
    *value += 20; 
} 

fn main() { 
    let mut x = 10; 
    let ref_x = &mut x; 

    let handles: Vec<_> = (0..10).map(|_| { 
     thread::spawn(move || { 
      break_law(ref_x); 
      println!("{:?}", x); 
     }) 
    }).collect(); 

    for h in handles { 
     h.join().unwrap(); 
    } 
} 
+0

此修改觸發編譯錯誤:'x'活不夠長。但是我認爲'x'應該有比'ref_x'更長的生命週期,直到最後一個括號。 –

+0

@AselanDu我認爲你看到的那個編譯器錯誤的問題是用'spawn'創建的線程可能會超出它生成的範圍。這意味着從它引用的所有內容必須具有「靜態」的生命週期。由於x將在'main'的末尾被刪除,'ref_x'不能具有''static''的生命週期。 – crhino