在结构中创建安全 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]
}