Rust conditionals: Difference between revisions

From wikinotes
 
(9 intermediate revisions by the same user not shown)
Line 13: Line 13:
</blockquote><!-- if statement -->
</blockquote><!-- if statement -->


= Ternary operator =
= assign if =
<blockquote>
<blockquote>
<syntaxhighlight lang="rust">
<syntaxhighlight lang="rust">
let weather = if season == "fall" { "lovely" } else { "fine I guess" } // ternary
let weather = if season == "fall" { "lovely" } else { "fine I guess" } // ternary operator
</syntaxhighlight>
</syntaxhighlight>
</blockquote><!-- Ternary operator -->
</blockquote><!-- Ternary operator -->


= Pattern Matching =
= match =
<blockquote>
== Basics ==
<blockquote>
<blockquote>
Like a switch statement,<br>
Like a switch statement,<br>
but the compiler ensures the entire valid range of items is checked for.<br>
where compiler ensures that all possible options in datatype's range are handled,<br>
especially useful for enums.
that ensures the output type is the same for all branches (<code>panic!()/break/return</code> also allowed).
 
Especially useful for enums.


In the following case, if <code>_</code> was omitted<br>
In the following case, if <code>_</code> was omitted<br>
Line 45: Line 49:
}
}
</syntaxhighlight>
</syntaxhighlight>
</blockquote><!-- Basics -->


== Matching Enums ==
<blockquote>
When matching a parametrized enum, you can access the tuple/struct/value that is bound to it
When matching a parametrized enum, you can access the tuple/struct/value that is bound to it
<syntaxhighlight lang="rust">
<syntaxhighlight lang="rust">
Line 56: Line 63:
let pet = Pet::Lizard(5);
let pet = Pet::Lizard(5);
match pet {
match pet {
     Cat(name, age) => { format!("cat, name={}, age={}", name, age) },
     Pet::Cat(name, age) => { format!("cat, name={}, age={}", name, age) },
     Dog(dog) => { format!("dog, name={dog.name}, age={dog.age}") },
     Pet::Dog(dog)       => { format!("dog, name={dog.name}, age={dog.age}") },
     Lizard(age) => { format!("lizard, age={}", age) }
     Pet::Lizard(age)   => { format!("lizard, age={}", age) }
}
}
</syntaxhighlight>
</syntaxhighlight>
</blockquote><!-- Matching Enums -->
== Matching Option ==
<blockquote>
Option is just an enum, generally if you don't have a specific behaviour for <code>None</code>,<br>
you return a new <code>None</code> in that branch.<br>
However this an opportunity to fail if it is an appropriate location for it.
<syntaxhighlight lang="rust">
match some_value {
    Some(x) => "you received a value!",
    None    => None,
}
</syntaxhighlight>
</blockquote><!-- Matching Option -->
== Matching Ranges ==
<blockquote>
<syntaxhighlight lang="rust">
match val {
    i32::MIN..0 => "less than zero",
    0..5 => "is zero to five",
    5..i32::MAX => "is over five",
}
</syntaxhighlight>
<syntaxhighlight lang="rust">
use std::cmp::Ordering;
// todo
</syntaxhighlight>
</blockquote><!-- Matching Ranges -->
</blockquote><!-- Pattern Matching -->
</blockquote><!-- Pattern Matching -->
= if let =
<blockquote>
if let is essentially a one-branch <code>match</code>,<br>
only caring about the value if it is non-none.<br>
if <code>my_value</code> is <code>None</code>, then it returns <code>None</code> and the block does not run.
it does not take advantage of exhaustiveness checks.
<syntaxhighlight lang="rust">
if let Some(x) = my_value {
    println!("The value {} was bound!!", x);
}
</syntaxhighlight>
</blockquote><!-- if let -->

Latest revision as of 23:54, 9 February 2023

if statement

if num < 5 {
    // ..
} else if {
    // ..
} else {
    // ..
}

assign if

let weather = if season == "fall" { "lovely" } else { "fine I guess" } // ternary operator

match

Basics

Like a switch statement,
where compiler ensures that all possible options in datatype's range are handled,
that ensures the output type is the same for all branches (panic!()/break/return also allowed).

Especially useful for enums.

In the following case, if _ was omitted
you'd need to ensure the full range of possible i32 numbers were supported!.

// if num is '1', returns 'a'
// if num is >2, returns 'c'
let result = match num {
    1 => "a",
    2 => "b",
    _ => "c",   // anything other than 1 or 2
}

You can match multiple values

let result = match num {
    1 | 3 | 5 => "one three or five",
    _ => "something else"
}

Matching Enums

When matching a parametrized enum, you can access the tuple/struct/value that is bound to it

enum Pet {
    Cat(String, u8),
    Dog{name: String, age: u8},
    Lizard(u8),
}

let pet = Pet::Lizard(5);
match pet {
    Pet::Cat(name, age) => { format!("cat, name={}, age={}", name, age) },
    Pet::Dog(dog)       => { format!("dog, name={dog.name}, age={dog.age}") },
    Pet::Lizard(age)    => { format!("lizard, age={}", age) }
}

Matching Option

Option is just an enum, generally if you don't have a specific behaviour for None,
you return a new None in that branch.
However this an opportunity to fail if it is an appropriate location for it.

match some_value {
    Some(x) => "you received a value!",
    None    => None,
}

Matching Ranges

match val {
    i32::MIN..0 => "less than zero",
    0..5 => "is zero to five",
    5..i32::MAX => "is over five",
}
use std::cmp::Ordering;

// todo

if let

if let is essentially a one-branch match,
only caring about the value if it is non-none.
if my_value is None, then it returns None and the block does not run.

it does not take advantage of exhaustiveness checks.

if let Some(x) = my_value {
    println!("The value {} was bound!!", x);
}