为什么在i32的情况下,Rust强制在移动线程时使用move?

甘菊

我是Rust的新手,看来我在这里严重缺少一些概念。

use std::thread;

fn main() {
    let mut children = vec![];

    //spawn threads
    for i in 0..10 {
        let c = thread::spawn(|| {
            println!("thread id is {}", i);
        });
        children.push(c);
    }

    for j in children {
        j.join().expect("thread joining issue");
    }
}

它失败并显示以下错误:

error[E0373]: closure may outlive the current function, but it borrows `i`, which is owned by the current function

由于iis的类型i32,并且不涉及任何引用,Rust不应该复制该值而不是强制使用move

无伴奏合唱

您原始问题的答案是println!借用其论点。但是,正如您在注释中指出的那样,即使(显然)将整数移入闭包仍然会导致编译错误。

出于此答案的目的,我们将使用此代码。

fn use_closure<F: FnOnce() + 'static>(_: F) {}

fn main() {
    let x: i32 = 0;
    use_closure(|| {
        let _y = x;
    });
}

(操场)

use_closure模拟thread::spawn原始代码中的操作:它使用类型为的闭包'static

尝试编译会产生错误

error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
 --> src/main.rs:5:17
  |
5 |     use_closure(|| {
  |                 ^^ may outlive borrowed value `x`
6 |         let _y = x;
  |                  - `x` is borrowed here
  |
note: function requires argument type to outlive `'static`
 --> src/main.rs:5:5
  |
5 | /     use_closure(|| {
6 | |         let _y = x;
7 | |     });
  | |______^
help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
  |
5 |     use_closure(move || {
  |                 ^^^^^^^

等一下

6 |         let _y = x;
  |                  - `x` is borrowed here

为什么在x那里借?不应该是副本吗?答案在于闭包的“捕获模式”。文档中

编译器更喜欢通过不可变借项,唯一的不可变借项(见下文),可变借项以及最后通过移动来捕获封闭变量。它将选择允许闭包编译的首选方法。仅根据闭包表达式的内容进行选择;编译器不考虑周围的代码,例如所涉及变量的生存期。

正是由于x具有Copy类型,所以闭包本身可以仅用不可变的借位进行编译。鉴于不可改变的借x(叫它bor),我们可以做我们的分配_y使用_y = *bor这不是“移出引用后的数据”,因为这是副本而不是移动。

但是,由于闭包借用了局部变量,因此它的类型将不是'static,因此无法在use_closure或中使用thread::spawn

尝试使用not类型的相同代码Copy,实际上效果很好,因为强制闭包x通过移动来捕获

fn use_closure<F: FnOnce() + 'static>(_: F) {}

fn main() {
    let x: Vec<i32> = vec![];
    use_closure(|| {
        let _y = x;
    });
}

(操场)


当然,您已经知道,解决方案是move在闭包前面使用关键字。这将强制将所有捕获的变量移到闭包中。由于不会借用该变量,因此闭包将具有静态类型,并且可以在use_closure或中使用thread::spawn

fn use_closure<F: FnOnce() + 'static>(_: F) {}

fn main() {
    let x: i32 = 0;
    use_closure(move || {
        let _y = x;
    });
}

(操场)

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在这种情况下,借入的价值不能长期使用(Vec <&Fn(i32)-> i32>)

来自分类Dev

为什么在Win8-64上使用Rust,i32的性能要好于i64?

来自分类Dev

为什么在c ++中可以在没有#include线程的情况下使用std :: thread?

来自分类Dev

为什么在没有警告的情况下强制使用by来强制data.table中的列不起作用?

来自分类Dev

在某些情况下,使用ByteBuddy子类化类时,会收到IllegalAccessErrors。为什么?

来自分类Dev

为什么在这种情况下使用memset

来自分类Dev

为什么我们可以在不强制转换的情况下将32位的立即数整数赋给short类型的变量?

来自分类Dev

为什么在枚举和切换的情况下需要强制展开?

来自分类Dev

在不移动鼠标的情况下使用Synchronize在线程上调用的方法不会返回

来自分类Dev

在我的情况下使用线程池

来自分类Dev

在这种简单情况下,为什么notifyAll()无法恢复其他线程?

来自分类Dev

为什么在Servlet的情况下需要实现单线程模型?

来自分类Dev

在这种简单情况下,为什么notifyAll()不恢复其他线程?

来自分类Dev

为什么我的线程锁在这种情况下失败了?

来自分类Dev

在缺少移动构造函数的情况下,复制构造函数称为?这是为什么?

来自分类Dev

在缺少移动构造函数的情况下,复制构造函数称为?这是为什么?

来自分类Dev

为什么不能在没有sudo的情况下删除或移动这些文件?

来自分类Dev

为什么在这种情况下,未调用move构造函数?

来自分类Dev

为什么在不设置级别的情况下使用factor()时,输出未按字母顺序排序?

来自分类Dev

在所有情况下都以“可运行的实施”为赢家时,为什么存在“扩展线程”

来自分类Dev

我不明白为什么我在这种情况下会使用字母i

来自分类Dev

为什么在使用GString的情况下,groovy映射键评估在类似情况下会有不同的表现?

来自分类Dev

为什么在使用GString的情况下,groovy映射键评估在类似情况下会有不同的表现?

来自分类Dev

使用共享内存时如何在不选择的情况下阻止线程?

来自分类Dev

Javascript 矩阵赋值在填充的情况下与使用循环创建矩阵的情况不同。为什么?

来自分类Dev

为什么当ng-show可以在两种情况下都可以工作时为什么使用ng-hide

来自分类Dev

为什么在不进行强制转换的情况下将任何内容转换为更具体的类型

来自分类Dev

为什么在选择器不起作用的情况下强制类型转换起作用

来自分类Dev

为什么不能在没有强制转换的情况下指向指针,访问结构成员?

Related 相关文章

  1. 1

    在这种情况下,借入的价值不能长期使用(Vec <&Fn(i32)-> i32>)

  2. 2

    为什么在Win8-64上使用Rust,i32的性能要好于i64?

  3. 3

    为什么在c ++中可以在没有#include线程的情况下使用std :: thread?

  4. 4

    为什么在没有警告的情况下强制使用by来强制data.table中的列不起作用?

  5. 5

    在某些情况下,使用ByteBuddy子类化类时,会收到IllegalAccessErrors。为什么?

  6. 6

    为什么在这种情况下使用memset

  7. 7

    为什么我们可以在不强制转换的情况下将32位的立即数整数赋给short类型的变量?

  8. 8

    为什么在枚举和切换的情况下需要强制展开?

  9. 9

    在不移动鼠标的情况下使用Synchronize在线程上调用的方法不会返回

  10. 10

    在我的情况下使用线程池

  11. 11

    在这种简单情况下,为什么notifyAll()无法恢复其他线程?

  12. 12

    为什么在Servlet的情况下需要实现单线程模型?

  13. 13

    在这种简单情况下,为什么notifyAll()不恢复其他线程?

  14. 14

    为什么我的线程锁在这种情况下失败了?

  15. 15

    在缺少移动构造函数的情况下,复制构造函数称为?这是为什么?

  16. 16

    在缺少移动构造函数的情况下,复制构造函数称为?这是为什么?

  17. 17

    为什么不能在没有sudo的情况下删除或移动这些文件?

  18. 18

    为什么在这种情况下,未调用move构造函数?

  19. 19

    为什么在不设置级别的情况下使用factor()时,输出未按字母顺序排序?

  20. 20

    在所有情况下都以“可运行的实施”为赢家时,为什么存在“扩展线程”

  21. 21

    我不明白为什么我在这种情况下会使用字母i

  22. 22

    为什么在使用GString的情况下,groovy映射键评估在类似情况下会有不同的表现?

  23. 23

    为什么在使用GString的情况下,groovy映射键评估在类似情况下会有不同的表现?

  24. 24

    使用共享内存时如何在不选择的情况下阻止线程?

  25. 25

    Javascript 矩阵赋值在填充的情况下与使用循环创建矩阵的情况不同。为什么?

  26. 26

    为什么当ng-show可以在两种情况下都可以工作时为什么使用ng-hide

  27. 27

    为什么在不进行强制转换的情况下将任何内容转换为更具体的类型

  28. 28

    为什么在选择器不起作用的情况下强制类型转换起作用

  29. 29

    为什么不能在没有强制转换的情况下指向指针,访问结构成员?

热门标签

归档