14.1 Introduction to Option Types
In many programming scenarios, values can be absent. Rust addresses this by making ‘absence’ explicit at the type level. Rather than letting you ignore a missing value until it potentially causes a runtime error, Rust forces you to consider both presence and absence at compile time.
14.1.1 The Option Enum
Rust’s standard library defines Option<T> as:
#![allow(unused)] fn main() { enum Option<T> { Some(T), None, } }
Some(T): Indicates a valid value of typeT.None: Signifies that no value is present.
These variants are in the Rust prelude, so you do not need to bring them into scope manually. You can simply write:
#![allow(unused)] fn main() { let value: Option<i32> = Some(42); let no_value: Option<i32> = None; }
Type Inference and None
When you write Some(...), Rust usually infers the type automatically. However, if you only write None, the compiler may need a hint:
#![allow(unused)] fn main() { let missing = None; // Error: Rust doesn't know which type you need here }
To fix this, you specify the type:
#![allow(unused)] fn main() { let missing: Option<u32> = None; }
14.1.2 Why Use an Option Type?
Many everyday programming tasks require the ability to represent ‘no value’:
- Searching a collection may fail to find the target.
- A configuration file might omit certain settings.
- A database query can return zero results.
- Iterators naturally end and have no further items to return.
By using Option<T>, Rust requires you to handle both the ‘found’ (Some) and ‘not found’ (None) cases, preventing you from accidentally ignoring missing data. This is a significant departure from C, where NULL or a sentinel value might be used without always forcing an explicit check.
14.1.3 Tony Hoare and the ‘Billion-Dollar Mistake’
Tony Hoare introduced the concept of the null reference in 1965. He later described it as his ‘billion-dollar mistake’ because of the vast expense and bugs caused by dereferencing NULL in languages like C. Rust tackles this head-on with Option<T>, making the absence of a value a deliberate part of the type system.
14.1.4 Null Pointers Versus Option
In C, forgetting to check for NULL before dereferencing a pointer can lead to crashes or undefined behavior. Rust solves this by requiring you to acknowledge the possibility of absence through Option<T>. You cannot turn an Option<T> into a T without handling the None case, ensuring that ‘null pointer dereferences’ are caught at compile time, not at runtime.