A commonly-acclaimed feature of Rust is its match
keyword: a “conditional on steroids”. match
lets you take the value of an expression and compare it against a bunch of values—or, more generally, patterns.
As you write and read Rust, you will notice that this keyword is used everywhere because it’s the way to access certain types, like Option
values or error codes.
For example:
match node.get_parent() { // node is an Option<Something>.
Some(parent) => {
// Do something with "parent", which we know points to a node.
},
None => {
// There is no parent so do something else.
}
}
In the snippet above, we have a match
statement with two arms. One key detail to observe is how the parent
variable, which was used as a pattern to peek inside the Some
value, is only available in the first arm. The None
arm has no access to the parent
variable, which is obvious because there is no parent in this case.
OK so… I just said statement. But as we saw in the previous post, everything in Rust is an expression—and you guessed right, match
is no exception. A match
can be assigned to a variable:
let parent = match node.get_parent() {
Some(parent) => parent,
None => "ROOT",
};
// Do something with "parent", which we know points to a node.
The most attractive feature of match
, however, and the primary reason I am writing about it in its own post, is that the arms are evaluated in order and must be exhaustive: any expression fed to match
must have a case where it’s accepted. For example, this results in a build error:
enum Shape { Circle, Triangle, Square }
fn shape_name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle => "circle",
Shape::Triangle => "triangle",
// ERROR: We forgot the Shape::Square case.
}
}
This is an extremely useful feature to deliver safe and future-proof code: by using match
, there is no way you can forget to handle a case even if the code later changes to cover more cases. E.g. if you ever decided to add a new shape to the enum
above, the compiler would refuse to build your code, so you would be forced to add the missing arms. (Yes, I know, other languages like C++ will warn you if switch
statements miss cases on enumerations… but will only do so under these specific circumstances; match
is useful outside of enum
s.)
To conclude: the reason I find this interesting is because this feature aligns perfectly well with my Readability: Explicitly state complementary conditions post.