仍然在努力改变Rust的思维方式,现在我有了这个用例 - 一个用于多线程TcpListener
的配置:
use std::net::{TcpListener, TcpStream, ToSocketAddrs};
use std::thread;
fn main() {
serve("127.0.0.1:3333", Configuration { do_something: true });
}
//#[derive(Copy, Clone)]
pub struct Configuration {
pub do_something: bool,
}
pub fn serve<A: ToSocketAddrs>(addr: A, conf: Configuration) {
let listener = TcpListener::bind(addr).expect("bind failed");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
thread::spawn(move || {
handle_client(stream, &conf);
});
}
Err(e) => {
println!("Connection failed: {}", e);
}
}
}
}
fn handle_client(stream: TcpStream, conf: &Configuration) {
if conf.do_something {
//stream....
}
}
我很高兴TcpStream
被handle_client
消费,这是它的目的,但为什么Configuration
必须被复制为每个线程?我想只有一个副本并与所有线程共享一个不可变引用。那可能吗?或许我错过了这一点。
如果我通过引用传递Copy
,为什么我需要Clone
和Configuration
特征?这让我很困惑:
error[E0382]: capture of moved value: `conf`
--> src/main.rs:19:64
|
19 | thread::spawn(move || { handle_client(stream, &conf); });
| ------- ^^^^ value captured here after move
| |
| value moved (into closure) here
|
= note: move occurs because `conf` has type `Configuration`, which does not implement the `Copy` trait
答案 0 :(得分:6)
实现void f2(A* const a2)
(此处附带Copy
)只能解决问题,因为实现它会允许编译器隐式复制Clone
结构,将复制的值传递给线程。
它需要按值传递变量,因为你告诉编译器将Configuration
所有使用的值都放入闭包中:
move
thread::spawn(move || {
// ^^^^ HERE
handle_client(stream, &conf);
});
关键字的完整目的是告诉编译器&#34;不,不要尝试推断变量在这个闭包中的使用方式,只需移动一切都在&#34;。
当你move
move
时,编译器说&#34;好的,我将&conf
移动到闭包中然后引用它&#34;。< / p>
在您的情况下,您只需删除conf
关键字:
move
如果您确实需要能够使用thread::spawn(|| {
handle_client(stream, &conf);
});
关键字和传递参考,则需要移动参考:
move
这仍然不允许您的代码编译,因为不能保证引用超过线程。这在Passing a reference to a stack variable to a scoped thread中进行了详尽的讨论。