Nullability and Optionality

In C#, null is often used to represent a value that is missing, absent or logically uninitialized. For example:

int? some = 1; int? none = null;

Rust has no null and consequently no nullable context to enable. Optional or missing values are instead represented by Option<T>. The equivalent of the C# code above in Rust would be:

let some: Option<i32> = Some(1); let none: Option<i32> = None;

Option<T> in Rust is practically identical to 'T option from F#.

Control flow with optionality

In C#, you may have been using if/else statements for controlling the flow when using nullable values.

uint? max = 10; if (max is { } someMax) { Console.WriteLine($"The maximum is {someMax}."); // The maximum is 10. }

You can use pattern matching to achieve the same behavior in Rust:

let max = Some(10u32); match max { Some(max) => println!("The maximum is {}.", max), // The maximum is 10. None => () }

It would even be more concise to use if let:

let max = Some(10u32); if let Some(max) = max { println!("The maximum is {}.", max); // The maximum is 10. }

Null-conditional operators

The null-conditional operators (?. and ?[]) make dealing with null in C# more ergonomic. In Rust, they are best replaced by using the map method. The following snippets show the correspondence:

string? some = "Hello, World!"; string? none = null; Console.WriteLine(some?.Length); // 13 Console.WriteLine(none?.Length); // (blank)
let some: Option<String> = Some(String::from("Hello, World!")); let none: Option<String> = None; println!("{:?}", some.map(|s| s.len())); // Some(13) println!("{:?}", none.map(|s| s.len())); // None

Null-coalescing operator

The null-coalescing operator (??) is typically used to default to another value when a nullable is null:

int? some = 1; int? none = null; Console.WriteLine(some ?? 0); // 1 Console.WriteLine(none ?? 0); // 0

In Rust, you can use unwrap_or to get the same behavior:

let some: Option<i32> = Some(1); let none: Option<i32> = None; println!("{:?}", some.unwrap_or(0)); // 1 println!("{:?}", none.unwrap_or(0)); // 0

Note: If the default value is expensive to compute, you can use unwrap_or_else instead. It takes a closure as an argument, which allows you to lazily initialize the default value.

Null-forgiving operator

The null-forgiving operator (!) does not correspond to an equivalent construct in Rust, as it only affects the compiler's static flow analysis in C#. In Rust, there is no need to use a substitute for it.