如何声明一个结构数组并稍后对其进行初始化? [英] How to declare an array of structs and initialize it later?

查看:27
本文介绍了如何声明一个结构数组并稍后对其进行初始化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个结构:

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

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

I want to have two Points in two different variables. I want to declare them first and initialize later. It works fine with separate values:

let p0: Point;
let p1: Point;

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

我想用数组做同样的事情:

I want to do the same but with an array:

let p: [Point; 2];

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

不起作用,因为我收到编译错误:

Doesn't work as I get a compilation error:

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() 吗?

Why does it behave differently for single variables and arrays? Can I do it without using Default::default()?

推荐答案

Rust 要求对数组中的每个元素进行初始化.编译器实际上无处可跟踪每个值的初始化状态.

Rust requires that every element in an array is initialized. There's literally nowhere for the compiler to track the initialized state of each value.

手工方式包括使用不安全的 Rust 代码和 MaybeUninit 和原始指针操作.然后程序员负责正确维护所有要求:

The by-hand way to do it involves using unsafe Rust code paired with MaybeUninit and raw pointer manipulation. Then the programmer is responsible for correctly upholding all of the requirements:

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 之前验证所有元素都已填充,否则代码具有未定义的行为.

The programmer has to validate that all of the elements have been filled before assume_init is called, otherwise the code has undefined behavior.

相反,使用 ArrayVec 要容易得多,它处理所有对你来说不安全的逻辑:

Instead, it's much easier to use ArrayVec, which handles all the unsafe logic for you:

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()
    };
}

另见:

这篇关于如何声明一个结构数组并稍后对其进行初始化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆