我想在多个线程中更改一个可变变量。我知道这不是线程安全的,但我想知道 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
这看起来很奇怪,但我该如何纠正呢?为什么?
最佳答案
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<(_,)>
, _
表示类型参数还没有足够的信息来完全推断)。
关于multithreading - 在多个线程中改变共享可变变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33499889/