crustinitializationmemory-safety

Why must be structure initialized in rust?


In C I can use a struct that has not yet been initialized. I tried this code in Rust:

struct User {
    username: String,
    email: String,
    sign_in_count: u64,
    active: bool,
}

fn main(){
    let mut user1: User;
    user1.active = false;
}

But it produced a compilation error:

error[E0381]: assign to part of possibly-uninitialized variable: `user1`
  --> src/main.rs:10:5
   |
10 |     user1.active = false;
   |     ^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `user1`

Why is this allowed in C but an error in Rust?


Solution

  • All values in Rust must have an initialized value if they are to be safely accessed.

    This is because operations using uninitialized values have undefined behaviour. What this may result in is the compiler accidentally miscompiling your code.

    Avoiding miscompilation is one of the prime goals of Rust; including other forms of undefined behaviour such as data races, dereferencing an invalid pointer, or mutating data that other code assumes to not change. Read more here.

    In C, you can access those values; thereby permitting the compiler to miscompile your code since you've broken contract. In Rust however, you aren't allowed to do that.

    In some languages, such as C# you replace uninitialized values with null. We have a similar concept: Options, which are either Some(value) or there is None.


    Please note that if the compiler miscompiles your code due to undefined behaviour associated with unsound operations, it's not the compiler's fault. It's not trying to look for this either; it is just trying to optimize your code. If I give you a baseball bat and you used it to smack your head, then you'd be misusing it, it wouldn't be my fault, as a designer, since I couldn't foresee you misusing it.


    There are ways to do what you can do in C though. These are unsafe and are strongly discouraged for regular operations though, so please try your hardest to look for another solution before jumping into unnecessary unsafe and possibly unsound behaviour.

    Use std::mem::MaybeUninit and read the Rust nomicon before dabbling in unsafe.