I have a struct:
struct Point {
x: u32,
y: u32,
}
I want to have two Point
s 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`
Why does it behave differently for single variables and arrays? Can I do it without using Default::default()
?
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.
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()
};
}
The programmer has to validate that all of the elements have been filled before assume_init
is called, otherwise the code has undefined behavior.
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()
};
}
See also:
Arrays are fixed size in Rust and Rust requires that every element in an array is initialized - e.g. no undefined values.
In your case, I would do:
let p: [Point; 2] = [Point { x: 1, y: 2 }, Point { x: 2, y: 3 }];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With