我试过使用下面的代码:
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/