简体   繁体   English

Rust 2021 与 2018:特征 `std::marker::Send` 未实现 - 在 2021 版中执行此操作的正确方法是什么?

[英]Rust 2021 vs. 2018: trait `std::marker::Send` is not implemented - what is the correct way to do this in 2021 edition?

I am currently following a course on Rust and have found that there is a bit that compiles with the 2018 edition of Rust but not the 2021 edition.我目前正在学习关于 Rust 的课程,并发现有一些内容可以与 2018 版的 Rust 而不是 2021 版一起编译。 While I could just change my edition and continue on, I'd like to understand further what would be correct way to proceed if I were using the 2021 edition and why the difference occurs?虽然我可以更改我的版本并继续,但我想进一步了解如果我使用的是 2021 版本,正确的操作方法是什么,以及为什么会出现差异?

The error that comes with the 2021 edition is: 2021版附带的错误是:

let handle = std::thread::spawn(move || {
             ^^^^^^^^^^^^^^^^^^
             *mut [T] cannot be sent between threads safely
    threaded_fun(&mut *raw_s.0)
});
=help: ... the trait `Send` is not implemented for `*mut [T]`

The original code was working on multithreaded sort function, but I've tried to take out as much as I think I could so that it's just splitting out a vector and printing it's progress.原始代码正在处理多线程排序功能,但我试图尽可能多地取出,以便它只是拆分一个向量并打印它的进度。

use std::fmt::Debug;

struct RawSend<T>(*mut [T]); // one element tuple

unsafe impl<T> Send for RawSend<T> {}

pub fn threaded_fun<T: 'static + PartialOrd + Debug + Send>(v: &mut [T]) {
    if v.len() <= 1 {
        return;
    }
    let p = v.len()/2;
    println!("{:?}", v);

    let (a, b) = v.split_at_mut(p);

    let raw_a: *mut [T] = a as *mut [T];
    let raw_s = RawSend(raw_a);

    unsafe {
        let handle = std::thread::spawn(move || {
            threaded_fun(&mut *raw_s.0)
        });
        threaded_fun(&mut b[..]);

        // unsafe is required because compiler doesn't know we combine these
        handle.join().ok();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn threaded_test() {
        let mut v = vec![1,2,3,4,5,6,7,8,9,10];
        threaded_fun(&mut v);
        panic!(); // Test is just to activate the function. `cargo test`
    }
}

This is because Edition 2021 has partial captures in closures .这是因为2021 版在闭包中有部分捕获

What this means is that in Rust 2018,这意味着在 Rust 2018 中,

|| a.b

will capture "a" in its entirety, but in Rust 2021, it will only perform a partial capture of ab , and if the structure has other fields those remain available to the creator of the closure.将完整捕获“a”,但在 Rust 2021 中,它将仅执行部分捕获ab ,并且如果结构具有其他字段,则这些字段仍可供闭包的创建者使用。

In your case however, it means raw_s.0 is what's captured and used for the computation of the closure's traits, and since it's not Send (as it's a raw pointer) the closure is not Send anymore either.但是,在您的情况下,这意味着raw_s.0是捕获并用于计算闭包特征的内容,并且由于它不是Send (因为它是原始指针),因此闭包也不再是Send The change in traits computation was specifically noted in the editions changelog . 在版本变更日志中特别指出了特征计算的变化。

You can fix that by forcing a capture of the structure itself eg您可以通过强制捕获结构本身来解决此问题,例如

let raw_s = raw_s;

or或者

let _ = &raw_s;

Note that cargo has a cargo fix subcommand which can migrate this sort of changes for you (using the --edition flag).请注意,cargo 有一个cargo fix子命令,可以为您迁移此类更改(使用--edition标志)。

This is because edition 2021 changed how closures capture.这是因为 2021 版改变了闭包的捕获方式。 In 2018, they capture entire structs, but in 2021, they will capture individual struct members.在 2018 年,他们捕获整个结构,但在 2021 年,他们将捕获单个结构成员。

This causes the closure to attempt to capture the raw pointer ( raw_s.0 ) instead of the whole RawSend .这会导致闭包尝试捕获原始指针( raw_s.0 )而不是整个RawSend You can work around this by explicitly forcing raw_s to move:您可以通过显式强制raw_s移动来解决此问题:

    unsafe {
        let handle = std::thread::spawn(move || {
            let raw_s = raw_s;
            threaded_fun(&mut *raw_s.0)
        });
        threaded_fun(&mut b[..]);

        // unsafe is required because compiler doesn't know we combine these
        handle.join().ok();
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM