Arrays 如何创建和初始化不可变数组?
我想创建一个数组。我不需要数组是可变的,在创建时,我拥有计算数组第I个成员所需的所有信息。但是,我不知道如何在Rust中创建不可变数组 以下是我现在拥有的:Arrays 如何创建和初始化不可变数组?,arrays,immutability,rust,Arrays,Immutability,Rust,我想创建一个数组。我不需要数组是可变的,在创建时,我拥有计算数组第I个成员所需的所有信息。但是,我不知道如何在Rust中创建不可变数组 以下是我现在拥有的: let mut my_array: [f32; 4] = [0.0; 4]; for i in 0..4 { // some calculation, doesn't matter what exactly my_array[i] = some_function(i); } 这就是我想要的: let my_array: [
let mut my_array: [f32; 4] = [0.0; 4];
for i in 0..4 {
// some calculation, doesn't matter what exactly
my_array[i] = some_function(i);
}
这就是我想要的:
let my_array: [f32; 4] = array_factory!(4, some_function);
如何在Rust中实现这一点?尝试将宏扩展到以下内容:
let my_array = {
let mut tmp: [f32, ..4u] = [0.0, ..4u];
for i in range(0u, 4u) {
tmp[i] = somefunction(i);
}
tmp
};
我不知道的是,这是否经过了适当的优化,以避免将
tmp
移动到myu数组
。但对于4个f32值(128位),这可能不会产生显著差异。以下是宏定义和示例用法:
macro_rules! array_factory(
($size: expr, $factory: expr) => ({
unsafe fn get_item_ptr<T>(slice: *mut [T], index: usize) -> *mut T {
(slice as *mut T).offset(index as isize)
}
let mut arr = ::std::mem::MaybeUninit::<[_; $size]>::uninit();
unsafe {
for i in 0..$size {
::std::ptr::write(get_item_ptr(arr.as_mut_ptr(), i), $factory(i));
}
arr.assume_init()
}
});
);
fn some_function(i: usize) -> f32 {
i as f32 * 3.125
}
fn main() {
let my_array: [f32; 4] = array_factory!(4, some_function);
println!("{} {} {} {}", my_array[0], my_array[1], my_array[2], my_array[3]);
}
有一个很好的理由。此答案的早期版本使用了
mem::uninitialized
,它不是内存安全的:如果在初始化数组时发生死机(因为工厂函数死机),并且数组的项类型有一个析构函数,编译器将插入代码来调用数组中每个项的析构函数;即使是尚未初始化的项目maybeunit
避免了这个问题,因为它将初始化的值封装在Rust中,这是Rust中的一种魔法类型,可以防止析构函数自动运行。+1很好!但我几乎可以肯定你的作业是错的。您需要改用::std::ptr::write
。否则对未初始化的值调用drop
。我想知道[std::uninitialized(),…N]
是一个no op还是涉及N个函数调用。我认为对整个数组使用单个std::uninitialized()
是一种更好的方法。在本例中,它似乎用两次移动来初始化整个阵列。使用-O0,它正在调用未初始化()
,但不是在循环中。谢谢!但是来自C#,我有一个习惯,就是尽量避免不安全的块。(顺便说一句,这仍然是一个好习惯,还是我应该放弃它?)我是否正确地理解,您使用不安全块的唯一原因是不依赖于正在实现的Default::Default()
?@golergka:避免unsafe
仍然是一个好习惯。在本例中,它用于避免必须使用一些伪元素初始化数组的问题。
macro_rules! array_factory(
($size: expr, $factory: expr) => ({
let mut arr = [::std::default::Default::default(), ..$size];
for i in 0..$size {
arr[i] = $factory(i);
}
arr
});
)