16

配列の各要素を非定数式に初期化する必要があります。最初に配列の各要素を無意味な式に初期化することなく、それを行うことはできますか? これが私ができるようにしたいことの例です:

fn foo(xs: &[i32; 1000]) {
    let mut ys: [i32; 1000];

    for (x, y) in xs.iter().zip(ys.iter_mut()) {
        *y = *x / 3;
    }
    // ...
}

このコードは、コンパイル時エラーを示します。

error[E0381]: borrow of possibly uninitialized variable: `ys`
 --> src/lib.rs:4:33
  |
4 |     for (x, y) in xs.iter().zip(ys.iter_mut()) {
  |                                 ^^ use of possibly uninitialized `ys`

ysこの問題を解決するには、関数の最初の行を変更して、次のようにいくつかのダミー値で要素を初期化する必要があります。

let mut ys: [i32; 1000] = [0; 1000];

その余分な初期化を省略する方法はありますか? すべてをブロックにラップしunsafeても、違いはないようです。

4

1 に答える 1

16

場合によっては、次を使用できますstd::mem::MaybeUninit

use std::mem::MaybeUninit;

fn main() {
    let mut ys: MaybeUninit<[i32; 1000]> = MaybeUninit::uninit();
}

初期化されていない値へのアクセスは Rust では定義されていない動作であり、コンパイラーは のすべての値が読み取られる前に初期化されることを保証できないため、MaybeUninitラッパーを経由で削除することは安全ではありません。assume_initys

あなたの特定のケースは、ドキュメントの例の1つです。MaybeUninitこの実装の安全性に関する議論については、それを読んでください。

use std::mem::{self, MaybeUninit};

fn foo(xs: &[i32; 1000]) {
    // I copied this code from Stack Overflow without
    // reading why it is or is not safe.
    let ys: [i32; 1000] = {
        let mut ys: [MaybeUninit<i32>; 1000] = unsafe { MaybeUninit::uninit().assume_init() };

        let mut xs = xs.into_iter();

        for y in &mut ys[..] {
            if let Some(x) = xs.next().copied() {
                *y = MaybeUninit::new(x / 3);
            }
        }

        unsafe { mem::transmute(ys) }
    };
    // ...
}

配列に収集することはできませんが、代わりに配列があれば、次のVecことができます。

let ys: Vec<_> = xs.iter().map(|&x| x / 3).collect();

特定の問題については、着信配列を複製してから変更することもできます。

let mut ys = xs.clone();
for y in ys.iter_mut() { *y = *y / 3 }
于 2014-10-03T20:14:30.713 に答える