在结构中创建安全 overlapping/union 字段
Creating safe overlapping/union fields in structs
在 C++ 中,我可以创建如下结构:
union Vector4
{
struct { float x, y, z, w; };
float data[4];
};
因此我可以轻松地以字段或连续数组的形式访问数据。或者,我可以只创建一个指向第一个字段 x
的指针,然后从该指针读取一个连续的数组。
我知道有枚举,但我付不起额外的开销。我也知道我可以在 Rust 中创建联合,但它们要求我在访问它们的任何地方用 unsafe
乱扔我的代码。我觉得我不应该这样做,因为代码不是不安全的,因为底层数据总是表示为浮点数(而且我需要 C 布局 #[repr(C)]
所以编译器不会抛出字段的顺序).
我如何在 Rust 中实现它,以便我可以按名称访问字段,同时也可以轻松安全地访问整个结构的连续内存?如果这不可能,有没有办法让我可以安全地获取结构的一部分?
没有安全的联盟这回事。就个人而言,我认为固定大小的整数类型数组之间的转换应该被认为是安全的,但目前没有例外。
话虽这么说,但我完全 100% 不是工会 Vector4
。如您所见,Deref
用于隐藏不安全代码并使其成为可能,因此您可以根据使用它的上下文将 Vector4
视为结构或数组。transmute 也不是理想,但我觉得在这种情况下我可以证明这一点。如果您选择这样做,那么您可能还想实施 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]
}
在 C++ 中,我可以创建如下结构:
union Vector4
{
struct { float x, y, z, w; };
float data[4];
};
因此我可以轻松地以字段或连续数组的形式访问数据。或者,我可以只创建一个指向第一个字段 x
的指针,然后从该指针读取一个连续的数组。
我知道有枚举,但我付不起额外的开销。我也知道我可以在 Rust 中创建联合,但它们要求我在访问它们的任何地方用 unsafe
乱扔我的代码。我觉得我不应该这样做,因为代码不是不安全的,因为底层数据总是表示为浮点数(而且我需要 C 布局 #[repr(C)]
所以编译器不会抛出字段的顺序).
我如何在 Rust 中实现它,以便我可以按名称访问字段,同时也可以轻松安全地访问整个结构的连续内存?如果这不可能,有没有办法让我可以安全地获取结构的一部分?
没有安全的联盟这回事。就个人而言,我认为固定大小的整数类型数组之间的转换应该被认为是安全的,但目前没有例外。
话虽这么说,但我完全 100% 不是工会 Vector4
。如您所见,Deref
用于隐藏不安全代码并使其成为可能,因此您可以根据使用它的上下文将 Vector4
视为结构或数组。transmute 也不是理想,但我觉得在这种情况下我可以证明这一点。如果您选择这样做,那么您可能还想实施 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]
}