在采用“& mut self"(例如drop)的方法中加入线程会导致“无法移出借用的内容". [英] Joining a thread in a method that takes `&mut self` (like drop) results in "cannot move out of borrowed content"
问题描述
我想在new
方法内部创建一个线程,并在销毁该结构后将其停止:
I want to create a thread inside of the new
method and stop it after the struct is destroyed:
use std::thread;
struct Foo {
handle: thread::JoinHandle<()>,
}
impl Foo {
pub fn new(name: &str) -> Foo {
let name = name.to_string();
Foo {
handle: thread::spawn(move || {
println!("hi {}", name);
}),
}
}
pub fn stop(&mut self) {
self.handle.join();
}
}
fn main() {
let mut foo = Foo::new("test");
foo.stop();
}
这不能编译,我不明白为什么:
This doesn't compile, and I can not understand why:
error[E0507]: cannot move out of borrowed content
--> <anon>:15:9
|
15 | self.handle.join();
| ^^^^ cannot move out of borrowed content
在Rust的较新版本中:
And in newer versions of Rust:
error[E0507]: cannot move out of `self.handle` which is behind a mutable reference
--> src/main.rs:17:9
|
17 | self.handle.join();
| ^^^^^^^^^^^ move occurs because `self.handle` has type `std::thread::JoinHandle<()>`, which does not implement the `Copy` trait
如何解决此错误?
将来,我将为Foo
实现Drop
,并将从drop()
调用stop()
.
In the future, I will implement Drop
for Foo
, and will call stop()
from drop()
.
推荐答案
fn join(self) -> Result<T>
这意味着该方法按值(获取所有权/使用它)获取self
(接收者对象).但是您只能借用您的JoinHandle
;可变的,但仍然只是借来的,不是所有权.因此,您不能调用此方法,因为您不能将所有权从借用权移到该join()
方法中.
This means that the method takes self
(the receiver object) by values (taking the ownership/consuming it). But you only have a borrow to your JoinHandle
; a mutable one, but still merely a borrow, not the ownership. Thus you can't call this method, because you can't move the ownership out of your borrow into this join()
method.
解决此问题的一种简单方法是也通过stop()
方法中的值接受self
:
An easy way to fix that, is by accepting self
by value in the stop()
method, too:
pub fn stop(self) {
self.handle.join();
}
但是您会注意到在实现Drop
时这是不可能的,因为drop()
具有签名fn drop(&mut self)
! mm!但是,您可以使用一个小技巧,如下所述.请注意,在drop()
中加入线程可能不是一个好主意!阅读 Matthieu M.的答案以获取更多信息!
But you will notice that this isn't possible when implementing Drop
, because drop()
has the signature fn drop(&mut self)
! Bummer! But there is a little trick you can use, described below. Please be aware that joining threads in drop()
is probably not a good idea! Read Matthieu M.'s answer for more information on that!
如果出于某种原因仍然认为您确实要在drop()
中加入线程,则可以将JoinHandle
存储在Option<T>
中以保存它是否已经加入.如果您有Some(T)
,则可以使用方法
If you still think, for whatever reason, that you really want to join a thread in drop()
, you can store the JoinHandle
in an Option<T>
to save whether or not it's already joined. If you have a Some(T)
you can obtain a T
(by value!) from it by using the method Option::take()
. Then you can write:
fn drop(&mut self) {
// `self.handle` has the type `Option<JoinHandle<()>>` here!
if let Some(handle) = self.handle.take() {
handle.join().expect("failed to join thread");
}
}
这篇关于在采用“& mut self"(例如drop)的方法中加入线程会导致“无法移出借用的内容".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!