首页 > 解决方案 > 如何声明一个结构数组并稍后对其进行初始化?

问题描述

我有一个结构:

struct Point {
    x: u32,
    y: u32,
}

我想Point在两个不同的变量中有两个 s。我想先声明它们,然后再初始化。它适用于单独的值:

let p0: Point;
let p1: Point;

p0 = Point { x: 1, y: 2 };
p1 = Point { x: 2, y: 3 };

我想做同样的事情,但使用一个数组:

let p: [Point; 2];

p[0] = Point { x: 1, y: 2 };
p[1] = Point { x: 2, y: 3 };

当我收到编译错误时不起作用:

error[E0381]: use of possibly-uninitialized variable: `p`
 --> src/main.rs:9:5
  |
9 |     p[0] = Point { x: 1, y: 2 };
  |     ^^^^ use of possibly-uninitialized `p`

为什么单个变量和数组的行为不同?我可以不使用Default::default()吗?

标签: arraysstructrust

解决方案


Rust 要求数组中的每个元素都被初始化。编译器实际上无处跟踪每个值的初始化状态。

手动的方法是使用不安全的 Rust 代码与MaybeUninit原始指针操作配对。然后程序员负责正确维护所有要求:

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

#[derive(Debug)]
struct Point {
    x: u32,
    y: u32,
}

fn main() {
    // I copied this code from Stack Overflow without reading 
    // the prose that describes why this is or is not safe.
    let p = unsafe {
        // Future: MaybeUninit::uninit_array
        let mut p = MaybeUninit::<[Point; 2]>::uninit();

        // Future: MaybeUninit::first_ptr_mut
        let h = p.as_mut_ptr() as *mut Point;
        ptr::write(h.offset(0), Point { x: 1, y: 2 });
        ptr::write(h.offset(1), Point { x: 2, y: 3 });

        p.assume_init()
    };
}

程序员必须在调用之前验证所有元素是否已被填充assume_init,否则代码具有未定义的行为。

相反,它更容易使用ArrayVec,它为您处理所有不安全的逻辑:

use arrayvec::ArrayVec; // 0.5.1

struct Point {
    x: u32,
    y: u32,
}

fn main() {
    let p = {
        let mut p = ArrayVec::<[Point; 2]>::new();

        p.insert(0, Point { x: 1, y: 2 });
        p.insert(1, Point { x: 2, y: 3 });

        p.into_inner()
    };
}

也可以看看:


推荐阅读