Enumeration

Defining an Enum

enum IpAddrKind {
  V4,
  V6
}

struct IpAddr {
  kind: IpAddrKind,
  address: String,
}

let home = IpAddr {
	kind: IpAddrKind::V4,
	address: String::from("127.0.0.1"),
};

We can also put data directly into each enum variant:

enum IpAddr {
	V4(String),
	V6(String),
}
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));

Each num variant we define also becomes a function that constructs an instance of the enum. That is, IpAddr::V4() is a function call that takes a String argument and returns an instance of the IpAddr type.

There’s another advantage to using an enum rather than a struct: each variant can have different types and amounts of associated data.

Stand library way of defining:

We can define method on enum using impl:

The Option Enum and Its Advantages Over Null Values

The enum is defined by the standard library. The Option type encodes the very common scenario in which value could be something or it could be nothing.

Rust doesn’t have the null feature that many other languages have. Null is a value that means there is no value there. In languages with null, variables can always be in one of two states: null or not-null.

The Option<T> enum is so useful that it’s even included in the prelude. You can use Some and None directly without the Option:: prefix.

Because Option<T> and T (where T can be any type) are different types, the compiler won’t let us use an Option<T> value as if it were definitely a valid value.

So a invalid number cannot take part in the calculation with a valid number.

The match Control Flow Construct

Patterns That Bind to Values

Matches in Rust are exhaustive: we must exhaust every last possibility in order for the code to be valid. Especially in the case of Option<T>.

Catch-all Patterns and the _ Placeholder

Concise Control Flow with if let

We can think of if let as syntax sugar for a match that runs code when the value matches one pattern and then ignores all other values.

Last updated