Reputation: 135
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?
Upvotes: 3
Views: 2685
Reputation: 3999
As Optimistic Peach already said, this is mainly just the way Rust works. Everything needs to be initialized in Rust. It's the same with every other variable as well.
But the reason why Rust does it that way is not a problem with the compiler. As you know from C, the compiler there can compile the code without problems, even if variables don't get initialized. The problem is, that if you just define a variable without initializing it, the variable can be accessed and the value will be whatever is already in the memory location the variable is stored at.
Rust tries to be a language, that is very safe. Access to uninitialized memory has been often the cause of bugs, so it does want to prevent this. The designers could have chosen to use some default value to be used, when no default is given in the program code, but they decided to always require explicit default values.—That's more or less just a design choice they did.
Probably a reason for this design choice is that in Rust there are several types, where there are no obvious default values. In other languages as in C# you have the null
value that can be assigned to all references. In Rust you can have something similar to null
by using the Option<T>
as a type (instead of just T) and assign the None
value. But this only works if the programmer decided to use Option<T>
instead of just T
. What could be the default value for a variable of type std::fs::File
if there is no null
in Rust and the programmer didn't define an initial value?
Upvotes: 5
Reputation: 4288
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: Option
s, 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
.
Upvotes: 14