Tạo các trường chồng chéo / liên kết an toàn trong cấu trúc
Trong C ++, tôi có thể tạo các cấu trúc như sau:
union Vector4
{
struct { float x, y, z, w; };
float data[4];
};
vì vậy tôi có thể dễ dàng truy cập dữ liệu dưới dạng các trường hoặc dưới dạng một mảng liền kề. Ngoài ra, tôi chỉ có thể tạo một con trỏ đến trường đầu tiên x
và đọc từ con trỏ dưới dạng một mảng liền kề.
Tôi biết rằng có enums, nhưng tôi không thể trả thêm phí. Tôi cũng biết mình có thể tạo liên hiệp trong Rust, nhưng họ yêu cầu tôi phải xả mã của mình vào unsafe
nơi tôi đang truy cập chúng. Điều mà tôi cảm thấy mình không nên làm vì mã không an toàn vì dữ liệu cơ bản luôn được biểu diễn dưới dạng số nổi (và tôi cần bố cục C #[repr(C)]
để trình biên dịch không xoay quanh thứ tự của các trường).
Làm cách nào để triển khai điều này trong Rust để tôi có thể truy cập các trường theo tên nhưng cũng có quyền truy cập dễ dàng và an toàn vào bộ nhớ liền kề của toàn bộ cấu trúc? Nếu điều này là không thể, có cách nào để tôi có thể lấy một phần của cấu trúc một cách an toàn không?
Trả lời
Không có cái gọi là một công đoàn an toàn. Cá nhân tôi cho rằng chuyển đổi giữa các mảng có kích thước cố định của kiểu số nguyên nên được coi là an toàn, nhưng hiện tại không có ngoại lệ.
Điều đó đang được nói, đây là hoàn toàn 100% của tôi không phải là một công đoàn Vector4
. Như bạn có thể thấy, nó Deref
hoạt động để ẩn mã không an toàn và làm cho nó để bạn có thể coi Vector4
là một cấu trúc hoặc một mảng dựa trên ngữ cảnh mà nó được sử dụng. Việc chuyển đổi cũng không lý tưởng, nhưng tôi cảm thấy mình có thể biện minh cho điều đó trong trường hợp này. Nếu bạn chọn làm điều gì đó như thế này, thì bạn cũng có thể muốn thực hiện 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]
}