Enums are great for categorical data, where something, like an IP address, can belong to one category, such as IPv4 or IPv6. Enums are heavily used in Rust, unlike in C++. Example:
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
// Function that uses an enum as a parameter
fn coin_value(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
// Enums can contain data
enum Message {
Move { x: i32, y: i32 }, // Anonymous struct
Write(String),
ChangeColor(i32, i32, i32), // three i32 values
Quit,
}
// Method of Message
impl Message {
fn call(&self) {
// Body
}
}
fn main() {
// Use the namespace syntax to choose a category
let c = Coin::Dime;
println!("Coin value: {}", coin_value(c));
let m = Message::Write(String::from("hello"));
m.call();
}
Null references have caused lots of problems in other languages. To solve this, Rust created the Option
enum. In the Option
enum, there are two possibilities: Some
(not null) and None
(null). The Option
enum will not interact with none Option
data, thus you have to be aware of when using types that might be null, unlike C++ pointers 😁.
This enum is so popular in Rust that it is automatically loaded, Some
and None
can be used without namespacing them with Option
.
The Option
enum works well with the match
expression, verifying that you cover both the null and not null cases.
Basic definition:
enum Option<T> {
Some(T),
None,
}
Example use:
// With namespaceing
let some_number = Option::Some(2);
// Without namespacing
let another_number = Some(3);
let some_string = Some("Daltie");
// "Null"
let absent_number: Option<i32> = None; // Need to specify the type that Null would be otherwise
// Options and none options do not interact with each other natively
let x: i8 = 3;
let y: Option<i8> = Some(5);
//let sum = x + y; // Breaks
Function example:
fn add_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
fn main() {
let three = Some(3);
let four = add_one(three);
let none = add_one(None);
}