该#[repr(trasparent)]
属性将类型标记为具有与其单个非零大小字段相同的类型布局,但是当类型未调整大小时,这是否同样适用于所述类型的引用/指针?
具体来说,可我安全之间进行转换&MySlice<T>
,并&[T]
在下面的例子吗?
#[repr(transparent)]
struct MySlice<T>([T]);
let std_slice: &[i32] = &[ 1, 2, 3 ];
// is this safe?
let my_slice: &MySlice<i32> = unsafe {
std::mem::transmute(std_slice)
};
Run Code Online (Sandbox Code Playgroud)
根据The Rust Reference,struct
带有的单个字段#[repr(transparent)]
将具有相同的表示和 ABI。
这意味着 a 的 ABI 与 a 的 ABI&MySlice<T>
相同&[T]
,因为MySlice
没有其他字段,因此我们可以将其视为[T]
。因此,在它们之间进行转换是安全的。
但是,您这样做的方式是不合理的,实际上可能导致生命周期错误,因为std::mem::transmute
如果其类型参数有生命周期,则不会保留生命周期,指针转换也没有,尽管通常认为指针转换更安全,因为编译器可以如果您犯了错误,请进行干预。
因此,正确的创建方式&MySlice
如下:
#[repr(transparent)]
struct MySlice<T>([T]);
impl<T> MySlice<T> {
pub fn make<'a>(value: &'a [T]) -> &'a Self {
unsafe {
&*(value as *const [T] as *const Self)
}
}
}
Run Code Online (Sandbox Code Playgroud)
游乐场。
这将保留生命周期并避免transmute
.
此外,还可以使用union
s:
#[repr(transparent)]
struct MySlice<T>([T]);
union SliceRepr<'a, T> {
slice: &'a [T],
my_slice: &'a MySlice<T>,
}
impl<T> MySlice<T> {
pub fn make<'a>(value: &'a [T]) -> &'a Self {
unsafe {
SliceRepr { slice: value }.my_slice
}
}
}
Run Code Online (Sandbox Code Playgroud)
因为这也关心生命。