我想在多个线程中更改一个可变变量。我知道这不是线程安全的,但我想知道Rust编译器将如何处理它。因此,我使用range的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 `[closure@break_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 `[closure@break_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 `[closure@break_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这看起来很奇怪,但我该如何纠正呢?为什么?
发布于 2015-11-03 13:25:18
map的类型签名表示它接受类型参数(F),它是一个闭包(FnMut),它传递一个参数,即迭代器产生的类型((Self::Item)),并返回一个B (-> B)。您缺少的部分是论点:它需要是.map(|x| { ... })而不是.map(|| { ... })。
如果您不关心参数的值,您可以编写.map(|_| { ... }) (使用_模式忽略它),或者编写.map(|_i| { ... }),其中领先的_是表示变量意味着未使用的约定(它可以消除编译器对未使用变量的正常警告)。
FWIW,错误消息有点长,但它确实包括以下信息:
type mismatch: the type `[closure@break_law1.rs:10:28: 15:3 x:_]` implement
the trait `core::ops::FnMut<()>`,
but the trait `core::ops::FnMut<(_,)>` is required我用换行来突出区别:编译器抱怨您要传递给map的闭包不带参数(FnMut<()>),而实际上它想要一个带参数的闭包(FnMut<(_,)>,_表示一个类型参数,它还没有得到足够的信息来充分推断)。
发布于 2015-11-03 13:52:41
顺便说一句,即使像上面所示的修复了参数编号问题之后,您也不会得到您想要的行为。代码将成功编译,因为每个线程都将收到变量的变量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();
}
} https://stackoverflow.com/questions/33499889
复制相似问题