我想创建一个数组。我不需要数组是可变的,并且在创建时,我拥有计算数组的第i个成员所需的所有信息。但是,无法弄清楚如何在Rust中创建不可变数组。
这就是我现在所拥有的:
let mut my_array: [f32, ..4u] = [0.0, ..4u];
for i in range(0u,4u) {
// some calculation, doesn't matter what exactly
my_array[i] = some_function(i);
}
这就是我想要的:
let my_array: [f32, ..4u] = array_factory!(4u, some_function);
如何在Rust中实现这一目标?
答案 0 :(得分:2)
以下是带有示例用法的宏定义:
#![feature(macro_rules)]
macro_rules! array_factory(
($size: expr, $factory: expr) => ({
let mut arr = unsafe { [::std::mem::uninitialized(), ..$size] };
for i in range(0u, $size) {
unsafe {
::std::ptr::write(&mut arr[i], $factory(i));
}
}
arr
});
)
fn some_function(i: uint) -> f32 {
i as f32 * 3.125
}
fn main() {
let my_array: [f32, ..4u] = array_factory!(4u, some_function);
println!("{} {} {} {}", my_array[0], my_array[1], my_array[2], my_array[3]);
}
宏的主体基本上是你的第一个版本,但有一些变化:
std::mem::uninitialized()
是一个不安全的函数,因此我们必须在unsafe
块内调用它。std::ptr::write()
分配项目。赋值将尝试在数组中删除未初始化的值;效果取决于数组项类型(对于实现Copy
的类型,如f32
,它没有效果;对于其他类型,它可能会崩溃)。arr
的表达式结束。因此,该块表达式的结果为arr
。我们可以制作此宏的安全版本,而不是使用不安全的功能;但是,它要求数组项类型实现Default
特征。请注意,我们必须在此处使用常规赋值,以确保数组中的默认值是属性删除。
macro_rules! array_factory(
($size: expr, $factory: expr) => ({
let mut arr = [::std::default::Default::default(), ..$size];
for i in range(0u, $size) {
arr[i] = $factory(i);
}
arr
});
)
答案 1 :(得分:2)
现在,有一个(非常受欢迎的)板条箱可以做这件事:array_init
use array_init::array_init;
let my_array: [f32; 4] = array_init(some_function);
关于在 Rust 团队内部围绕数组创建抽象有很多讨论和演变。
例如,数组的 map 函数已经可用,它将在 rust 1.55 中变得稳定。
如果你愿意,你可以用 map 来实现你的功能:
#![feature(array_map)]
let mut i = 0usize;
result = [(); 4].map(|_| {v = some_function(i);i = i+1; v})
甚至还有围绕您的特定问题的讨论,您可以查看here
答案 2 :(得分:0)
尝试将宏扩展为:
let my_array = {
let mut tmp: [f32, ..4u] = [0.0, ..4u];
for i in range(0u, 4u) {
tmp[i] = somefunction(i);
}
tmp
};
我不知道这是否经过适当优化以避免将tmp
移至my_array
。但是对于4个f32值(128位),它可能没有显着差异。