如何最好地返回固定大小的数组而不创建具有虚拟值或手动展开的数组?

时间:2016-09-05 05:36:51

标签: arrays iterator rust

有时在循环中为固定大小的数组创建新值很有用:

fn foo(u: f64) -> [f64; 3] {
    let mut ret = [-1.0; 3];  // -1 is never used!
    for i in 0..3 {
        ret[i] = some_calculation(u, i);
    }
    return ret;
}

虽然这有效,但是创建一个填充了从未使用过的值的数组有点弱。

另一种方法是手动展开,但这对于较大的固定大小的数组来说并不是很好,或者当表达式涉及更多时,则给出的示例如下:

fn foo(u: f64) -> [f64; 3] {
    return [
        some_calculation(u, 0),
        some_calculation(u, 1),
        some_calculation(u, 2),
    ];
}

Rust是否提供了一种大致相当于Python列表理解的方法?

fn foo(u: f64) -> [f64; 3] {
    return [some_calculation(u, i) for i in 0..3];
}

我是一名初学者,对迭代器的经验很少。

3 个答案:

答案 0 :(得分:4)

Rust以默认模式(外部unsafe块)保证内存安全。

为了做到这一点,必须保证不会访问任何未初始化的内存,这会转换(对于数组)以确保无论发生什么都完全初始化它们。

一个聪明的分析可以检查你的循环是否会完全初始化它,但是可能无法证明它在更复杂的情况下有效,所以经验会不一致,并且当函数的简单改变突然导致时会发生震动你必须回到数组并完全初始化它,因为编译器不能再证明它有效。

因此,Rust采用了​​以下方法:

  1. 要求用户完全初始化阵列(通过提供可复制的值)
  2. 依靠优化器来消除冗余写入
  3. 如果第二步在特定设置中失败,用户可以使用unsafe { std::men::uninitialized() }告诉编译器它自己确保它已完全初始化。

    这种方法总是安全的,通常一样快......当你不幸使用Copy类型时,这种方法令人难以置信。在后一种情况下,一个简单的策略是首先构建一个Vec,然后将其元素移动到一个带有简单for循环的数组中,希望优化器应该在之后忽略所有不必要的东西。

答案 1 :(得分:1)

如果你可以使用不安全的阻止,你可以这样做:

fn foo(u: f64) -> [f64; 3] {
    let mut ret : [f64; 3] = unsafe { std::mem::uninitialized() };
    for i in 0..3 {
        ret[i] = some_calculation(u, i);
    }
    return ret;
}

答案 2 :(得分:0)

Rust中的数组总是被初始化:Rust referenceSO question on converting Vecs to arrays,所以这不应该是一个问题(特别是如果你是在最好的Rust练习之后)。