rust - 在 Rust 中的堆上创建一个固定大小的数组

标签 rust

我试过使用下面的代码:

fn main() {
    let array = box [1, 2, 3];
}

,在我的程序中,它会导致编译错误:error: obsolete syntax: ~[T] is no longer a type

AFAIU,Rust 中没有动态大小的数组(必须在编译时知道大小)。但是,在我的代码片段中,数组确实具有静态大小并且应该是类型 ~[T, ..3] (拥有大小为 3 的静态数组),而编译器说它具有类型 ~[T]。有什么深层原因导致无法在堆上分配静态大小的数组吗?

附言是的,我听说过 Vec

最佳答案

既然我来到了这里,其他人也可以。 Rust 一直在进步,在这个答案的关键时刻,Rust 稳定版为 1.53,夜间版为 1.55。

Box::new([1, 2, 3]) 是推荐的方式,并且可以完成它的工作,但是有一个问题:数组是在堆栈上创建的,然后复制过来到堆。这是 Box 的记录行为:

Move a value from the stack to the heap by creating a Box:

也就是说,它包含一个隐藏的memcopy,并且对于大数组,堆分配甚至会因堆栈溢出而失败。

const X: usize = 10_000_000;
let failing_huge_heap_array = [1; X];

thread 'main' has overflowed its stack
fatal runtime error: stack overflow

目前(Rust 1.53)有几种解决方法,最直接的是创建一个向量并将向量转换为盒装切片:

const X: usize = 10_000_000;
let huge_heap_array = vec![1; X].into_boxed_slice();

这行得通,但有两个小问题:它丢失了类型信息,应该是 Box<[i32; 10000000]> 现在是 Box<[usize]> 并且在堆栈上额外占用 16 个字节,而数组只占用 8 个字节。

...
println!("{}", mem::size_of_val(&huge_heap_array);

16

没什么大不了的,但它伤害了我个人的僧侣因素。

经过进一步研究,丢弃像 OP box [1, 2, 3] 这样每晚都需要的选项,它似乎以 #![feature(box_syntax)] 功能回归 和 arr crate,它很好但也需要 nightly,我发现最好的解决方案是在没有隐藏的 memcopy 的情况下在堆上分配数组 是 Simias 的建议

/// A macro similar to `vec![$elem; $size]` which returns a boxed array.
///
/// ```rustc
///     let _: Box<[u8; 1024]> = box_array![0; 1024];
/// ```
macro_rules! box_array {
    ($val:expr ; $len:expr) => {{
        // Use a generic function so that the pointer cast remains type-safe
        fn vec_to_boxed_array<T>(vec: Vec<T>) -> Box<[T; $len]> {
            let boxed_slice = vec.into_boxed_slice();

            let ptr = ::std::boxed::Box::into_raw(boxed_slice) as *mut [T; $len];

            unsafe { Box::from_raw(ptr) }
        }

        vec_to_boxed_array(vec![$val; $len])
    }};
}
const X: usize = 10_000_000;
let huge_heap_array = box_array![1; X];

它不会溢出堆栈,只占用 8 个字节,同时保留类型。

它使用 unsafe,但仅限于一行代码。在 box [1;X] 语法出现之前,恕我直言,这是一个干净的选择。

关于rust - 在 Rust 中的堆上创建一个固定大小的数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25805174/

相关文章:

rust - 将非 Rust 存储库声明为 Rust 项目中的依赖项的最佳方法是什么?

Rust:如何返回对 Rc<RefCell<HashMap<K, V>> 值的引用?

rust - 插入任意嵌套的HashMap

rust - 如何使用Serde::yaml遍历使用rust 的Yaml?

rust - 将带有可变引用的匹配放入函数时出现生命周期问题

rust - 编译器运行有某种顺序吗?

rust - 在 Rust 中为什么需要类型注释,即使它们在通用特征中明确指定

generics - 为什么此生命周期不是 "expire"?

rust - 将 futures 连接拆分为 sink 和 stream,并在两个不同的任务中使用它们

berkeley-db - 将 Rust 与 Berkeley DB 连接起来