在采用“& mut self"(例如drop)的方法中加入线程会导致“无法移出借用的内容". [英] Joining a thread in a method that takes `&mut self` (like drop) results in "cannot move out of borrowed content"

查看:149
本文介绍了在采用“& mut self"(例如drop)的方法中加入线程会导致“无法移出借用的内容".的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在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().

推荐答案

JoinHandle::join 是:

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");
    }
}

这篇关于在采用“&amp; mut self"(例如drop)的方法中加入线程会导致“无法移出借用的内容".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆