将引用强制转换为未定义大小的透明类型是否安全?

Frx*_*rem 8 rust

#[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)

Opt*_*ach 5

根据The Rust Referencestruct带有的单个字段#[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.


此外,还可以使用unions:

#[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)

因为这也关心生命。