การสร้างฟิลด์ทับซ้อน / ยูเนี่ยนที่ปลอดภัยในโครงสร้าง
ใน C ++ ฉันสามารถสร้างโครงสร้างดังนี้:
union Vector4
{
struct { float x, y, z, w; };
float data[4];
};
ดังนั้นฉันจึงสามารถเข้าถึงข้อมูลเป็นฟิลด์หรืออาร์เรย์ที่อยู่ติดกันได้อย่างง่ายดาย อีกวิธีหนึ่งฉันสามารถสร้างตัวชี้ไปยังฟิลด์แรกx
และอ่านจากตัวชี้เป็นอาร์เรย์ที่อยู่ติดกัน
ฉันรู้ว่ามี enum แต่ฉันไม่สามารถจ่ายค่าโสหุ้ยเพิ่มเติมได้ ฉันรู้ด้วยว่าฉันสามารถสร้างสหภาพแรงงานใน Rust ได้ แต่พวกเขาต้องการให้ฉันทิ้งรหัสของฉันด้วยunsafe
ที่ที่ฉันเคยเข้าถึงพวกเขา ซึ่งฉันรู้สึกว่าฉันไม่ควรต้องทำเนื่องจากโค้ดไม่ปลอดภัยเนื่องจากข้อมูลพื้นฐานมักจะแสดงเป็นโฟลต (และฉันต้องการโครงร่าง C #[repr(C)]
เพื่อให้คอมไพเลอร์ไม่โยนไปตามลำดับของฟิลด์)
ฉันจะใช้สิ่งนี้ใน Rust ได้อย่างไรเพื่อให้ฉันสามารถเข้าถึงฟิลด์ตามชื่อ แต่ยังสามารถเข้าถึงหน่วยความจำที่ต่อเนื่องกันของโครงสร้างทั้งหมดได้อย่างง่ายดายและปลอดภัย หากเป็นไปไม่ได้มีวิธีใดบ้างที่ฉันจะสามารถแบ่งส่วนโครงสร้างได้อย่างปลอดภัย?
คำตอบ
ไม่มีสิ่งที่เรียกว่าสหภาพที่ปลอดภัย โดยส่วนตัวแล้วฉันจะโต้แย้งว่าการส่งสัญญาณระหว่างอาร์เรย์ขนาดคงที่ของประเภทจำนวนเต็มควรได้รับการพิจารณาว่าปลอดภัย แต่ในขณะนี้ไม่มีข้อยกเว้น
ที่ถูกกล่าวว่าที่นี่มีทั้งหมด 100% Vector4
ของฉันไม่สหภาพแรงงาน อย่างที่คุณเห็นการDeref
ทำงานเพื่อซ่อนรหัสที่ไม่ปลอดภัยและทำให้คุณสามารถใช้Vector4
เป็นโครงสร้างหรืออาร์เรย์ตามบริบทที่ใช้การแปลงสัญญาณยังไม่เหมาะ แต่ฉันรู้สึกว่าฉันสามารถพิสูจน์ได้ ในกรณีนี้. หากคุณเลือกที่จะทำสิ่งนี้คุณก็อาจต้องการนำไปใช้DerefMut
เช่นกัน
use std::ops::Deref;
// I'm not sure if the repr(C) is needed in this case, but I added it just in case.
#[repr(C)]
pub struct Vector4<T> {
pub x: T,
pub y: T,
pub z: T,
pub w: T,
}
impl<T> Deref for Vector4<T>
where
T: Copy + Sized,
{
type Target = [T; 4];
fn deref(&self) -> &Self::Target {
use std::mem::transmute;
unsafe { transmute(self) }
}
}
pub fn main() {
let a = Vector4{
x: 37,
y: 21,
z: 83,
w: 94,
};
println!("{:?}", &a[..]);
// Output: [37, 21, 83, 94]
}