Memory 在结构中创建安全的重叠/并集字段 在C++中,我可以创建这样的结构: union Vector4 { struct { float x, y, z, w; }; float data[4]; };

Memory 在结构中创建安全的重叠/并集字段 在C++中,我可以创建这样的结构: union Vector4 { struct { float x, y, z, w; }; float data[4]; };,memory,rust,unions,Memory,Rust,Unions,因此,我可以轻松地以字段或连续数组的形式访问数据。或者,我可以创建一个指向第一个字段x的指针,并将其作为连续数组读取 我知道有枚举,但我不能支付额外的开销。我也知道我可以在Rust中创建联合,但它们要求我在访问它们的任何地方都使用safe。我觉得我不应该这样做,因为代码不是不安全的,因为底层数据总是用浮点数表示(而且我需要C-layout#[repr(C)],这样编译器就不会乱翻字段的顺序) 我将如何在Rust中实现这一点,以便我可以按名称访问字段,但也可以轻松安全地访问整个结构的连续内存?如果

因此,我可以轻松地以字段或连续数组的形式访问数据。或者,我可以创建一个指向第一个字段
x
的指针,并将其作为连续数组读取

我知道有枚举,但我不能支付额外的开销。我也知道我可以在Rust中创建联合,但它们要求我在访问它们的任何地方都使用
safe
。我觉得我不应该这样做,因为代码不是不安全的,因为底层数据总是用浮点数表示(而且我需要C-layout
#[repr(C)]
,这样编译器就不会乱翻字段的顺序)


我将如何在Rust中实现这一点,以便我可以按名称访问字段,但也可以轻松安全地访问整个结构的连续内存?如果这是不可能的,有没有一种方法可以让我安全地获取结构的一部分?

没有安全的联合。我个人认为,在整数类型的固定大小数组之间进行转换应该被认为是安全的,但目前没有例外

也就是说,这里是我的100%非联合
Vector4
。如您所见,
Deref
用于隐藏不安全的代码,并使其成为不安全的代码,因此您可以根据所使用的上下文将
Vector4
视为结构或数组。蜕变也不是很理想,但我觉得在这种情况下我可以证明这一点。如果您选择这样做,那么您可能还希望实现
DerefMut

使用std::ops::Deref;
//我不确定在这种情况下是否需要repr(C),但我添加它只是为了以防万一。
#[报告员(C)]
pub结构向量4{
酒吧x:T,
酒吧y:T,
酒吧z:T,
酒吧w:T,
}
矢量4的impl-Deref
哪里
T:复制+大小,
{
类型Target=[T;4];
fn deref(&self)->&self::Target{
使用std::mem::transmute;
不安全{transmute(self)}
}
}
pub fn main(){
设a=Vector4{
x:37,
y:21,
z:83,
w:94,
};
println!(“{:?},&a[…]);
//产出:[37,21,83,94]
}

没有安全的工会。我个人认为,在整数类型的固定大小数组之间进行转换应该被认为是安全的,但目前没有例外

也就是说,这里是我的100%非联合
Vector4
。如您所见,
Deref
用于隐藏不安全的代码,并使其成为不安全的代码,因此您可以根据所使用的上下文将
Vector4
视为结构或数组。蜕变也不是很理想,但我觉得在这种情况下我可以证明这一点。如果您选择这样做,那么您可能还希望实现
DerefMut

使用std::ops::Deref;
//我不确定在这种情况下是否需要repr(C),但我添加它只是为了以防万一。
#[报告员(C)]
pub结构向量4{
酒吧x:T,
酒吧y:T,
酒吧z:T,
酒吧w:T,
}
矢量4的impl-Deref
哪里
T:复制+大小,
{
类型Target=[T;4];
fn deref(&self)->&self::Target{
使用std::mem::transmute;
不安全{transmute(self)}
}
}
pub fn main(){
设a=Vector4{
x:37,
y:21,
z:83,
w:94,
};
println!(“{:?},&a[…]);
//产出:[37,21,83,94]
}

< /代码>将它存储为数组,并有方法通过名称工作访问字段?我非常肯定,任何一个象形的C++编译器都会优化一些类似于<代码>浮动GETX()的数据{{返回数据[0〕;}< /C> >与一个联合完全一样有效,这可能适用于Rust@apetranzilla是的,这是一个选择。我更喜欢C++版本的联合,因为GETT和SETTES都是非常集群化的,尤其是当它们只是一个原始的抽象时。联盟也觉得在用例上更加明确。但除此之外,这是最好的alternative@TedKleinBergman不幸的是,我认为没有更好的办法。Rust非常明确地说明了需要标记什么
不安全
,并且由于联合可能被用于构造非法位模式并导致UB,因此始终需要使用
不安全
来访问它们的字段。如果类型相当简单,则可以创建两个具有相同表示形式的独立结构,以及在这两个结构之间转换的方法,它应该被编译器优化出来,将它存储为数组,并有方法通过名称工作来访问字段?我非常肯定,任何一个象素的C++编译器都会优化一些类似于<代码>浮点GETX()的数据{{返回数据[0〕;}< /Cord>,就像联盟一样有效,这可能适用于Rust@apetranzilla对这是一个选择。我更喜欢C++版本的联合,因为GETT和SETTES都是非常集群化的,尤其是当它们只是一个原始的抽象时。联盟也觉得在用例上更加明确。但除此之外,这是最好的alternative@TedKleinBergman不幸的是,我认为没有更好的办法。Rust非常明确地说明了需要标记什么
不安全
,并且由于联合可能被用于构造非法位模式并导致UB,因此始终需要使用
不安全
来访问它们的字段。如果类型相当简单,您可以创建两个具有相同表示形式的独立结构以及在这两个结构之间转换的方法,这应该由编译器优化。
repr(C)
在这种情况下确实是必需的:默认表示形式不能保证布局匹配
[f32;4]
,根据定义。我个人不会使用
Deref
,而是
AsRef
,因为
Vector4
在语义上不是一个智能指针,而且OP似乎希望在数据的两个“视图”之间保持一定的分离(但这最终是一个主观决定)。这看起来是一个很好的解决方案