我目前正在學習關于 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`
}
}
uj5u.com熱心網友回復:
這是因為2021 版在閉包中有部分捕獲。
這意味著在 Rust 2018 中,
|| a.b
將完整捕獲“a”,但在 Rust 2021 中,它將僅執行部分捕獲a.b,并且如果結構具有其他欄位,則這些欄位仍可供閉包的創建者使用。
但是,在您的情況下,這意味著raw_s.0捕獲并用于計算閉包特征的內容,并且由于它不是Send(因為它是原始指標),因此閉包也Send不再是。在版本變更日志中特別指出了特征計算的變化。
您可以通過強制捕獲結構本身來解決此問題,例如
let raw_s = raw_s;
或者
let _ = &raw_s;
請注意,cargo 有一個cargo fix子命令可以為您遷移此類更改(使用--edition標志)。
uj5u.com熱心網友回復:
這是因為 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();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/487253.html
