我能以某种方式将盒装切片
Box<[[T;SIZE]]>
压平成Box<[T]>
吗?如果需要,可以使用 unsafe
。我拥有这个盒子,我想就地完成,而不制作不必要的副本。
它比看起来更复杂。有必要修改
PtrComponents::metadata
(该堆变量保存数组的长度),如切片len
的源所示。如果你不考虑这一点而只是改变盒子,它就没有正确的长度。
Vec::into_flattened()
。将 Box<[T]>
转换为 Vec<T>
始终是零成本;如果 Vec<T>
没有多余的容量(如果它源自 Box<[T]>
,情况总是如此),则将 Vec
转换为 Box<[T]>
是零成本。
#![feature(slice_flatten)]
pub fn flatten_box<T, const N: usize>(v: Box<[[T; N]]>) -> Box<[T]> {
Vec::from(v).into_flattened().into_boxed_slice()
}
可以这样写:
pub fn flatten_box<T, const DIM: usize>(v: Box<[[T; DIM]]>) -> Box<[T]> {
let old_len = v.len();
let old_ptr = Box::into_raw(v);
let new_len = old_len.checked_mul(DIM).expect("slice len overflow");
let new_ptr: *mut T = old_ptr.cast();
let new = std::ptr::slice_from_raw_parts_mut(new_ptr, new_len);
// SAFETY: the pointer was derived from an existing Box::into_raw call
// and has the original size and alignment and there are no outstanding
// references to the data
unsafe { Box::from_raw(new) }
}
解释一下:我们必须将
Box
解构为其原始组件,并使用新类型和长度重建一个新组件。使用 slice_from_raw_parts_mut
是使用切片的正确元数据构造指针的方法。你不必为此搞乱ptr::metadata
。
fn transmute<T, const N: usize>(b: Box<[[T; N]]>) -> Box<[T]> {
// SAFETY: raw pointer is created from Box and
// *mut [[T; N]] has the same aligment as *mut [T]
unsafe { Box::from_raw(Box::into_raw(b) as *mut [T]) }
}
编辑。这不会保留切片的长度。请参阅下面@eggyal 的评论以获取解决方案。