展平盒装数组切片

问题描述 投票:0回答:2

我可以以某种方式将 Rust 中的盒装切片

Box<[[T;SIZE]]>
压平为
Box<[T]>
(如果需要,不安全的代码也可以)吗?我拥有这个盒子,我想就地完成,而不制作不必要的副本。

它比看起来更复杂。有必要修改

PtrComponents::metadata
(这个堆变量保存数组的长度),如https://doc.rust-lang.org/src/core/slice/mod.rs.html#137

所示

如果你不考虑这一点


pub fn flatten_box<T,const DIM:usize>(v:Box<[[T;DIM]]>)->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(v) as *mut [T]) }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test6() {
        let v:Box<[[u32;13]]> = unsafe{Box::<[[u32;13]]>::new_uninit_slice(7).assume_init()};
        let l = v.len();
        let v = flatten_box(v);
        assert_eq!(v.len(),l*13);
    }
}

你会得到错误


Left:  7
Right: 91
<Click to see difference>

thread 'transmute::tests::test6' panicked at 'assertion failed: `(left == right)`
  left: `7`,
 right: `91`', vf\src\transmute.rs:76:9
arrays rust casting
2个回答
0
投票
你可以试试这个:
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 的评论以获取解决方案。


0
投票

可以这样写:

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 * DIM;
    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

© www.soinside.com 2019 - 2024. All rights reserved.