我尝试使用以下代码:
fn main() {
let array = box [1, 2, 3];
}
Run Code Online (Sandbox Code Playgroud)
,在我的程序中,它会导致编译错误:error: obsolete syntax: ~[T] is no longer a type。
AFAIU,Rust 中没有动态大小的数组(大小必须在编译时知道)。然而,在我的代码片段中,数组确实具有静态大小,并且应该是类型~[T, ..3](拥有大小为 3 的静态数组),而编译器说它具有类型~[T]。是否有任何深层原因导致无法在堆上分配静态大小的数组?
PS 是的,我听说过Vec。
Joh*_*ank 17
既然我到了这里,其他人也可能如此。Rust 已经向前发展,在这个答案中,Rust 的稳定版本为 1.53,每晚版本为 1.55。
Box::new([1, 2, 3])是推荐的方法,并且可以完成其工作,但是有一个问题:数组是在堆栈上创建的,然后复制到堆上。这是 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
Run Code Online (Sandbox Code Playgroud)
目前有几种解决方法(Rust 1.53),最简单的是创建一个向量并将向量转换为盒装切片:
const X: usize = 10_000_000;
let huge_heap_array = vec![1; X].into_boxed_slice();
Run Code Online (Sandbox Code Playgroud)
这可行,但有两个小问题:它丢失了类型信息,应该是 Box<[i32; 10000000]> 现在是 Box<[usize]> 并且另外在堆栈上占用 16 个字节,而数组只占用 8 个字节。
...
println!("{}", mem::size_of_val(&huge_heap_array);
16
Run Code Online (Sandbox Code Playgroud)
没什么大不了的,但这伤害了我个人的和尚因素。
经过进一步研究,放弃需要每晚的选项,例如 OP box [1, 2, 3],它似乎会带着该功能回来#![feature(box_syntax)],而 arr 板条箱很好,但也需要每晚,我发现在堆上分配数组而不隐藏的最佳解决方案memcopy
是西米亚斯的建议
/// 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)
const X: usize = 10_000_000;
let huge_heap_array = box_array![1; X];
Run Code Online (Sandbox Code Playgroud)
它不会溢出堆栈,仅占用 8 个字节,同时保留类型。
它使用 unsafe,但将其限制为单行代码。在语法出现之前box [1;X],恕我直言,这是一个干净的选项。
据我所知,盒子表达式是实验性的。您可以使用Box::new()类似下面的代码来抑制警告。
fn main() {
let array1 = Box::new([1, 2, 3]);
// or even
let array2: Box<[i32]> = Box::new([1, 2, 3]);
}
Run Code Online (Sandbox Code Playgroud)
请查看下面 Shepmaster 的评论,因为它们是不同的类型。