请帮帮我,我完全糊涂了。
我如何使这段代码工作?
我需要改变线程中的结构成员…
#[derive(Debug)]
struct S {
str: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
str: "a".to_string(),
b: false,
i: 0,
});
let mut threads = vec![];
for s in vec_s {
{
let mut _s = &s;
threads.push(std::thread::spawn(move || {
_s.b = true;
_s.str = "b".to_string();
_s.i = 1;
}));
}
}
for thread in threads {
let _ = thread.join();
}
dbg!(&vec_s);
}
编译器输出大量错误:
error[E0594]: cannot assign to `_s.b`, which is behind a `&` reference
--> src/main.rs:23:17
|
23 | _s.b = true;
| ^^^^^^^^^^^ cannot assign
error[E0594]: cannot assign to `_s.str`, which is behind a `&` reference
--> src/main.rs:24:17
|
24 | _s.str = "b".to_string();
| ^^^^^^ cannot assign
error[E0594]: cannot assign to `_s.i`, which is behind a `&` reference
--> src/main.rs:25:17
|
25 | _s.i = 1;
| ^^^^^^^^ cannot assign
error[E0597]: `s` does not live long enough
--> src/main.rs:21:26
|
21 | let mut _s = &s;
| ^^ borrowed value does not live long enough
22 | threads.push(std::thread::spawn(move || {
| __________________________-
23 | | _s.b = true;
24 | | _s.str = "b".to_string();
25 | | _s.i = 1;
26 | | }));
| |______________- argument requires that `s` is borrowed for `'static`
27 | }
28 | }
| - `s` dropped here while still borrowed
error[E0382]: borrow of moved value: `vec_s`
--> src/main.rs:34:10
|
9 | let mut vec_s = vec![];
| --------- move occurs because `vec_s` has type `Vec<S>`, which does not implement the `Copy` trait
...
19 | for s in vec_s {
| ----- `vec_s` moved due to this implicit call to `.into_iter()`
...
34 | dbg!(&vec_s);
| ^^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `vec_s`
--> /home/martin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/collect.rs:261:18
|
261 | fn into_iter(self) -> Self::IntoIter;
| ^^^^
help: consider iterating over a slice of the `Vec<S>`'s content to avoid moving into the `for` loop
|
19 | for s in &vec_s {
| +
您正在尝试执行多线程。多线程访问的所有内容都必须是线程安全的。此外,Rust非常严格(零未定义行为容忍),编译器必须理解你的代码是线程安全的。
这里最大的问题是Rust的借用检查器不理解你的线程在某个点被连接。因此,它不允许您创建对S
对象的引用,因为它无法证明这些引用存在了多长时间。Rust必须能够证明它们在你的S
对象被丢弃之前被销毁;这是Rust的borrow checker安全保证的一部分。
对于特定的用例,Rust引入了线程作用域。有了它们,编译器最终可以理解线程的生存期。
修复了一些次要的所有权问题(使用&mut vec_s
为循环,否则vec_s
对象被循环消耗),现在可以工作了:
#[derive(Debug)]
struct S {
s: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
s: "a".to_string(),
b: false,
i: 0,
});
std::thread::scope(|scope| {
let mut threads = vec![];
for s in &mut vec_s {
threads.push(scope.spawn(move || {
s.b = true;
s.s = "b".to_string();
s.i = 1;
}));
}
for thread in threads {
let _ = thread.join();
}
});
dbg!(&vec_s);
}
[src/main.rs:31] &vec_s = [
S {
s: "b",
b: true,
i: 1,
},
]
另一个优化:
如果您不实际使用JoinHandle
s进行错误传播或类似操作,那么在本例中根本不需要它们。scope
已经自动连接它在作用域结束时产生的所有线程:
#[derive(Debug)]
struct S {
s: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
s: "a".to_string(),
b: false,
i: 0,
});
std::thread::scope(|scope| {
for s in &mut vec_s {
scope.spawn(move || {
s.b = true;
s.s = "b".to_string();
s.i = 1;
});
}
});
dbg!(&vec_s);
}
[src/main.rs:27] &vec_s = [
S {
s: "b",
b: true,
i: 1,
},
]