如何在Rust 1.0中的堆上分配数组?

Mic*_*ael 12 arrays heap rust

已经有一个问题,但与Rust 0.13有关,语法似乎已经改变.从当前文档中我了解到在堆上创建数组将是这样的:

fn main() {
    const SIZE: usize = 1024 * 1024;
    Box::new([10.0; SIZE]);
}
Run Code Online (Sandbox Code Playgroud)

但是当我运行这个程序时,我收到以下错误:

thread '<main>' has overflowed its stack
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

DK.*_*DK. 16

问题是数组Box::new作为参数传递给函数,这意味着必须首先创建它,这意味着它必须在堆栈上创建.

你要求编译器在堆栈上创建8兆字节的数据:这就是溢出它的东西.

解决方案是根本不使用固定大小的数组,而是使用Vec.我能想到的最简单的方法就是赚Vec800万10.0:

fn main() {
    const SIZE: usize = 1024 * 1024;
    let v = vec![10.0; SIZE];
}
Run Code Online (Sandbox Code Playgroud)

或者,如果由于某种原因你宁愿使用迭代器:

use std::iter::repeat;

fn main() {
    const SIZE: usize = 1024 * 1024;
    let v: Vec<_> = repeat(10.0).take(SIZE).collect();
}
Run Code Online (Sandbox Code Playgroud)

应该只执行单个堆分配.

请注意,您可以随后使用该方法Vec将其转换为a .Box<[_]>into_boxed_slice

也可以看看:

  • 你应该可以使用`vec![10.0; 1024*1024]`. (3认同)
  • 请注意,有“box”语法应该可以帮助解决此问题,但它现在不稳定,我不确定它是否支持数组的直接堆放置。 (2认同)

小智 12

接受的答案非常不令人满意,因为有时我们确实希望在堆上分配的数组以保留类型级别的大小信息。现在可以使用 const 泛型稍微改进约翰内斯的答案。我们可以使用如下函数来代替宏:

fn vec_to_boxed_array<T: Copy, const N: usize>(val: T) -> Box<[T; N]> {
    let boxed_slice = vec![val; N].into_boxed_slice();

    let ptr = Box::into_raw(boxed_slice) as *mut [T; N];

    unsafe { Box::from_raw(ptr) }
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*ank 10

我也遇到了这个问题,最终在 Rust 的堆上创建固定大小的数组中找到了完整的答案。

答案的要点是这个宏:

/// 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])
    }};
}
Run Code Online (Sandbox Code Playgroud)

我最喜欢它,因为它简单地给了你OP想要的东西:

一个数组,它可以与稳定的 Rust 一起使用。