구조체에서 안전한 겹침 / 결합 필드 만들기
C ++에서는 다음과 같은 구조를 만들 수 있습니다.
union Vector4
{
struct { float x, y, z, w; };
float data[4];
};
따라서 데이터에 필드 또는 연속 배열로 쉽게 액세스 할 수 있습니다. 또는 첫 번째 필드에 대한 포인터를 만들고 포인터에서 x
연속 배열로 읽을 수 있습니다.
열거 형이 있다는 것을 알고 있지만 추가 오버 헤드를 지불 할 수 없습니다. 또한 Rust에서 유니온을 만들 수 있다는 것을 알고 있지만, unsafe
액세스하는 곳마다 코드를 흩뿌 려야 합니다. 기본 데이터가 항상 수레로 표현되기 때문에 코드가 안전하지 않기 때문에 필요하지 않다고 생각합니다 ( #[repr(C)]
컴파일러가 필드의 순서를 버리지 않도록 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]
}