初始化固定长度数组的正确方法是什么?

srk*_*ing 21 arrays rust

我在初始化固定长度数组时遇到问题. 到目前为止,我的尝试都导致了"使用可能未初始化的变量:foo_array"错误:

#[derive(Debug)]
struct Foo { a: u32, b: u32 }

impl Default for Foo {
    fn default() -> Foo { Foo{a:1, b:2} }
}

pub fn main() {
    let mut foo_array: [Foo; 10];

    // Do something here to in-place initialize foo_array?

    for f in foo_array.iter() {
        println!("{:?}", f);
    }
}
Run Code Online (Sandbox Code Playgroud)
error[E0381]: use of possibly uninitialized variable: `foo_array`
  --> src/main.rs:13:14
   |
13 |     for f in foo_array.iter() {
   |              ^^^^^^^^^ use of possibly uninitialized `foo_array`
Run Code Online (Sandbox Code Playgroud)

我实现了Default特性,但Rust似乎并没有像默认情况下那样调用C++构造函数.

初始化固定长度数组的正确方法是什么?我想做一个有效的就地初始化而不是某种副本.

相关:为什么默认(结构值)数组初始化需要复制特征?

相关:有没有办法不必两次初始化数组?

A.B*_*.B. 20

安全但效率低下的解决方案:

#[derive(Copy, Clone, Debug)]
struct Foo {
    a: u32,
    b: u32,
}

fn main() {
    let mut foo_array = [Foo { a: 10, b: 10 }; 10];
}
Run Code Online (Sandbox Code Playgroud)

由于您特别要求没有副本的解决方案:

use std::{mem, ptr};

#[derive(Debug)]
struct Foo {
    a: u32,
    b: u32,
}

// We're just implementing Drop to prove there are no unnecessary copies.
impl Drop for Foo {
    fn drop(&mut self) {
        println!("Destructor running for a Foo");
    }
}

pub fn main() {
    let array = unsafe {
        // Create an uninitialized array.
        let mut array: [Foo; 10] = mem::uninitialized();

        for (i, element) in array.iter_mut().enumerate() {
            let foo = Foo { a: i as u32, b: 0 };

            // Overwrite `element` without running the destructor of the old value.
            // Since Foo does not implement Copy, it is moved.
            ptr::write(element, foo)
        }

        array
    };

    for element in array.iter() {
        println!("{:?}", element);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你对`mem :: uninitialized()`的调用和数组完全初始化的点之间有任何恐慌,那么这段代码就会被破坏,而不是恐慌安全.如果Foo是"POD"类型,那么它很好.请注意,只要您引入泛型(并在初始化循环中调用特征方法),那么您可能无法保证不再出现恐慌. (6认同)
  • @AB:为什么第一个解决方案效率低下?(幼稚的问题,我真的不知道......) (2认同)
  • 如果您需要构造一个元素彼此不同的数组,例如一组扑克牌,则效率很低。在标准的 52 张卡片组中,您最终会制作 51 个不必要的副本。 (2认同)

Ibr*_*med 11

最简单的方法是派生Copy您的类型并用它初始化数组,复制元素N时间:

#[derive(Copy)]
struct Foo {
    a: u32,
    b: u32,
}

let mut foo_array = [Foo { a: 1, b: 2 }; 10];
Run Code Online (Sandbox Code Playgroud)

如果您想避免复制,有几个选择。您可以使用该Default特征:

let mut foo_array: [Foo; 10] = Default::default();
Run Code Online (Sandbox Code Playgroud)

但是,这仅限于最多 32 个元素的数组。借助 const 泛型,标准库现在可以Default所有数组提供支持。然而,由于正在研究的微妙原因,这将是一个向后不兼容的更改。

现在,您可以利用const数组重复表达式中也允许值的事实:

const FOO: Foo = Foo { a: 1, b: 2 };

let mut foo_array = [FOO; 10];
Run Code Online (Sandbox Code Playgroud)

如果您每晚使用,您可以使用array::map

#![feature(array_map)]

let mut foo_array = [(); 10].map(|_| Foo::default())
Run Code Online (Sandbox Code Playgroud)

  • `array::map` 稳定上线!现在这就是这个问题的最佳答案。 (2认同)

hei*_*991 5

您可以使用arrayvec板条箱

货代

[package]
name = "initialize_array"
version = "0.1.0"
authors = ["author"]
edition = "2018"

[dependencies]
arrayvec = "0.4.10"
Run Code Online (Sandbox Code Playgroud)

src / main.rs

use arrayvec::ArrayVec; 
use std::iter;

#[derive(Clone)]
struct Foo {
    a: u32,
    b: u32,
}

fn main() {
    let foo_array: [Foo; 10] = iter::repeat(Foo { a: 10, b: 10 })
        .collect::<ArrayVec<_>>()
        .into_inner()
        .unwrap_or_else(|_| unreachable!());
}
Run Code Online (Sandbox Code Playgroud)