Согласно Rust Reference , одиночное поле struct
с #[repr(transparent)]
будет иметь одинаковое представление и ABI.
Это означает, что 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)
}
}
}
Детская площадка .
Это сохраняет срок службы и позволяет избежать 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
}
}
}
Поскольку это также заботится о время жизни.