如何解决在 Rust 中将 `struct` 转换为切片是否安全?
我有一些struct
,像这样:
struct MyStruct<T> {
field1: T,field2: T,field3: T,}
我对 struct
的了解和确信:
- 所有字段的类型相同;
- 所有字段都是
Sized
; - 每个
struct
(在本例中为3
)的确切字段数;
在我的项目中,像切片一样访问 struct
可能很有用。所以我做了什么:
impl<T> AsRef<[T]> for MyStruct<T> {
fn as_ref(&self) -> &[T] {
let ptr = self as *const Self;
let ptr2 = ptr as *const T;
unsafe { std::slice::from_raw_parts(ptr2,3) }
}
}
现在我可以像这样访问 MyStruct
的字段:
let s = MyStruct { field1: 1.0,field2: 2.0,field3: 3.0 };
s.as_ref()[1]
我已经在 dev
和 release
模式下测试了一些示例,但没有发现任何错误。我仍然不确定这种指针魔术。
Rust 不能保证内存布局会保留字段的顺序。另一方面,据我所知,只有当 struct
具有不同大小的字段并且需要对齐时才会发生。
所以我真的很好奇:
impl<T> AsRef<[T]> for MyStruct<T> {
fn as_ref(&self) -> &[T] {
let tmp: &[T; 3] = unsafe { std::mem::transmute(self) };
tmp.as_ref()
}
}
解决方法
- 是否存在任何违反防锈安全保证的行为?
是的,订单无法保证。尽管不太可能改变,但 Rust 的 ABI 并不稳定,因此 Rust 编译器的未来版本可能会有不同的表现。
您可以强制使用 C ABI,这将使其安全:
#[repr(C)]
struct MyStruct<T> {
field1: T,field2: T,field3: T,}
避免 unsafe
的可能更好的方法是将字段存储在数组中,然后提供访问器:
struct MyStruct<T> {
fields: [T; 3],}
impl<T> MyStruct<T> {
fn field1(&self) -> &T {
&self[0]
}
fn field1_mut(&mut self) -> &mut T {
&mut self[0]
}
// etc,you could generate these with a macro if there are a lot
}
- 此变体与下一个变体之间在安全或性能方面是否存在差异?
这些很可能编译成相同的东西。如果您不确定,请测试。对于简单的事情,您可以将代码传递到 rust.godbolt.org 中并比较程序集。
- 我应该使用 Union 来代替这个技巧吗?
这也只有使用 #[repr(C)]
才安全。我看不出在这里使用 union
有什么明显的好处,但这意味着您必须使用甚至更多 unsafe
代码,所以它似乎没有就像一个好主意。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。