我想在多个线程中更改可变变量。我知道这不是线程安全的,但我想知道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 `[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
这看起来很奇怪,但我该如何纠正呢?为什么?
答案 0 :(得分:0)
map
的类型签名是说类型参数(F
)是一个闭包(FnMut
),传递一个参数是迭代器产生的类型((Self::Item)
)并返回B
(-> B
)。您遗失的部分是参数:它必须是.map(|x| { ... })
而不是.map(|| { ... })
。
如果您不关心参数的值,可以使用.map(|_| { ... })
模式忽略它来编写_
,或者.map(|_i| { ... })
,其中前导{{1}是一个约定,表示变量意图未使用(它使编译器对未使用变量的正常警告静音)。
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<(_,)>
表示尚未获得足够信息以进行完全推断的类型参数。
答案 1 :(得分: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();
}
}