如何在 Rust 1.0 中的堆上分配数组?
How to allocate arrays on the heap in Rust 1.0?
已经有一个 question for this but related to Rust 0.13 and the syntax seems to have changed. From the current documentation 我知道在堆上创建一个数组是这样的:
fn main() {
const SIZE: usize = 1024 * 1024;
Box::new([10.0; SIZE]);
}
但是当我 运行 这个程序时,我得到以下错误:
thread '<main>' has overflowed its stack
我做错了什么?
问题是数组作为参数传递给 Box::new
函数,这意味着它必须先创建 ,这意味着它必须在堆栈上创建。
您要求编译器在堆栈上创建 8 兆字节 的数据:这就是它溢出的原因。
解决方案是完全不使用固定大小的数组,而是 Vec
。我能想到的制作 800 万 10.0
的 Vec
的最简单方法是:
fn main() {
const SIZE: usize = 1024 * 1024;
let v = vec![10.0; SIZE];
}
或者,如果出于某种原因您更愿意使用迭代器:
use std::iter::repeat;
fn main() {
const SIZE: usize = 1024 * 1024;
let v: Vec<_> = repeat(10.0).take(SIZE).collect();
}
这应该只执行一次堆分配。
请注意,您随后可以使用 into_boxed_slice
方法将 Vec
转换为 Box<[_]>
。
另请参阅:
我也 运行 参与其中,并首先在 Creating a fixed-size array on heap in 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])
}};
}
这是我最喜欢的,因为它只是给了你 OP 想要的东西:
一个数组,并且它与稳定的 rust 一起工作。
接受的答案非常不令人满意,因为有时我们确实希望在堆上分配的数组在类型级别保留大小信息。现在可以使用 const 泛型稍微改进 Johannes 的回答。我们可以使用如下函数代替宏:
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) }
}
已经有一个 question for this but related to Rust 0.13 and the syntax seems to have changed. From the current documentation 我知道在堆上创建一个数组是这样的:
fn main() {
const SIZE: usize = 1024 * 1024;
Box::new([10.0; SIZE]);
}
但是当我 运行 这个程序时,我得到以下错误:
thread '<main>' has overflowed its stack
我做错了什么?
问题是数组作为参数传递给 Box::new
函数,这意味着它必须先创建 ,这意味着它必须在堆栈上创建。
您要求编译器在堆栈上创建 8 兆字节 的数据:这就是它溢出的原因。
解决方案是完全不使用固定大小的数组,而是 Vec
。我能想到的制作 800 万 10.0
的 Vec
的最简单方法是:
fn main() {
const SIZE: usize = 1024 * 1024;
let v = vec![10.0; SIZE];
}
或者,如果出于某种原因您更愿意使用迭代器:
use std::iter::repeat;
fn main() {
const SIZE: usize = 1024 * 1024;
let v: Vec<_> = repeat(10.0).take(SIZE).collect();
}
这应该只执行一次堆分配。
请注意,您随后可以使用 into_boxed_slice
方法将 Vec
转换为 Box<[_]>
。
另请参阅:
我也 运行 参与其中,并首先在 Creating a fixed-size array on heap in 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])
}};
}
这是我最喜欢的,因为它只是给了你 OP 想要的东西:
一个数组,并且它与稳定的 rust 一起工作。
接受的答案非常不令人满意,因为有时我们确实希望在堆上分配的数组在类型级别保留大小信息。现在可以使用 const 泛型稍微改进 Johannes 的回答。我们可以使用如下函数代替宏:
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) }
}