[英]Rust 2021 vs. 2018: trait `std::marker::Send` is not implemented - what is the correct way to do this in 2021 edition?
我目前正在学习关于 Rust 的课程,并发现有一些内容可以与 2018 版的 Rust 而不是 2021 版一起编译。 虽然我可以更改我的版本并继续,但我想进一步了解如果我使用的是 2021 版本,正确的操作方法是什么,以及为什么会出现差异?
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]`
原始代码正在处理多线程排序功能,但我试图尽可能多地取出,以便它只是拆分一个向量并打印它的进度。
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`
}
}
这是因为2021 版在闭包中有部分捕获。
这意味着在 Rust 2018 中,
|| a.b
将完整捕获“a”,但在 Rust 2021 中,它将仅执行部分捕获ab
,并且如果结构具有其他字段,则这些字段仍可供闭包的创建者使用。
但是,在您的情况下,这意味着raw_s.0
是捕获并用于计算闭包特征的内容,并且由于它不是Send
(因为它是原始指针),因此闭包也不再是Send
。 在版本变更日志中特别指出了特征计算的变化。
您可以通过强制捕获结构本身来解决此问题,例如
let raw_s = raw_s;
或者
let _ = &raw_s;
请注意,cargo 有一个cargo fix
子命令,可以为您迁移此类更改(使用--edition
标志)。
这是因为 2021 版改变了闭包的捕获方式。 在 2018 年,他们捕获整个结构,但在 2021 年,他们将捕获单个结构成员。
这会导致闭包尝试捕获原始指针( raw_s.0
)而不是整个RawSend
。 您可以通过显式强制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.