在Rust中创建不可变数组

时间:2014-10-18 00:09:36

标签: arrays immutability rust

我想创建一个数组。我不需要数组是可变的,并且在创建时,我拥有计算数组的第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中实现这一目标?

3 个答案:

答案 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位),它可能没有显着差异。