Rust tutorial, manage control flow with if, else-if, else
Tags: rust, programming, tutorial
Published: 2022-06-27 19:19:28

---
title: Rust tutorial, manage control flow with if, else-if, else
published: true
description: Learn how to manage control flow with if, else-if, else
tags: rust, programming, tutorial
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rx6owenmz21qa34gel29.png
---

In this chapter we will cover control flow, how to get your code to conditionally execute as well as be repeated when needed.

{% embed https://www.youtube.com/watch?v=Z0k2kecnetA  %}

> [Subscribe](https://www.youtube.com/channel/UC1Q3yUG4E0afRxccqqI3ycw?sub_confirmation=1)

## Introduction

In this chapter you will:

- Use if, else and else if to create different execution paths through your code.
- Apply loops to repeat statements.
- Add conditions to loops to either break or skip iterations.
- Iterate collections of data.

## Create a new execution path with `if`.

Let's consider these set of statements.

```rust
let salary = 220.2;
let other_income = 10.5;
let tax = 0.2; // percentage

let takehome_salary = (salary + other_income) * (1 as f32 - tax);
```

Above we have a calculation of someone's salary. Imagine though that someone is exempt from taxes if their income is below a certain income level, what then?

For this case, we can use an `if` construct to express this condition.

Our code can now be expressed like so:

```rust
let no_tax_value = 300.0;
let salary = 220.2;
let other_income = 10.5;
let tax = 0.2; // percentage

let mut takehome_salary = salary + other_income;

if (salary + other_income) > no_tax_value {
  takehome_salary = (salary + other_income) * (1 as f32 - tax); // tax deducted
}
```

The `if` clause evaluates an expression `(salary + other_income) > no_tax_value` that if evaluated to `true` will run the code within the brackets. If expression evaluates to `false` then the statement won't be run.

Your program has now two different execution paths depending on the sum of `salary + other_income`. 

## Else, what happens if `if` is false

You can extend your `if` with an `else` that runs if `if` evaluates to false.

In this example a customer is trying to withdraw an amount from their account and it shows an error message if it can't go through with it:

```rust
let mut account_balance = 100.0;
let amount = 101.50;
if account_balance - amount > 0 as f32 {
    account_balance -= amount;
} else {
    println!("Can't withdraw {}", amount);
}
```

From above, the `else` is placed right next to the `if`. In fact, it can't exist without the `if`. 

## Else if, if you have more than one condition

You've seen `if` and `else` so far, but there's one more construct `else if` that we can use. The idea with `else if` is to execute if the `if` evaluates to `false`. You can have any number of `else if`. Here's how to use it:

```rust
let card_number = 11;
if card_number == 11 {
    println!("Jack");
} else if card_number == 12 {
    println!("Queen");
} else if card_number == 13 {
    println!("King") 
} else if card_number == 14 || card_number == 1 {
    println!("Ace");
} else {
    println!("Card number is {}", card_number);
}
```

As you can see above, we have a number of `else if` constructs we can add after the initial `if`.

## `if` as an expression

Many languages out there has what is called a ternary expression. This means that a value is assigned to a variable in the same row. Here's how it can look in other languages:

```javascript
// javascript
let salary = 100;
let tax = 0.2;
let take_home_salary = salary > 200 ? salary * (1 as f32 - tax) : salary;
```

The value lies in not having to define an `if` with brackets that takes up several rows potentially. However, Rust can do this, like so:

```rust
let salary = 100.0;
let tax = 0.2;
let take_home_salary = if salary > 200.0 { salary * (1.0 - tax) } else {salary}; 
println!("Salary is {}", take_home_salary);
```

Note how the code inside of `if` and `else` don't have semicolons `;`, which makes them expressions. So here you are using the expression based version of `if` and `else`.

## Loops

Loops are used when you want to repeat a statement a number of times. That could be for example:

- command based program, where you ask a user for an input until they choose to quit the program
- iterating over something:
   - a collection of something, for example "orders" and process each order
   - iterating over files in a directory.

As you can see, there are many cases where looping a set of statements makes sense. Rust offers us many ways to loop.

## `loop`, looping statements

With this construct, you repeat statements forever or until the program is closed down. Here's example code:

```rust
loop {
    println!("forever");
} 
```

### Interrupt a loop with `break`

You can interrupt the looping mechanism though by adding a `break` to it. Consider the below code for how it would work:

```rust
let repeat_times: i32 = 5;
let mut index = 0;
loop {
  if index == repeat_times {
      break;
  }
  println!("Loop {}", index + 1);
  index += 1;

}
```

This program will print the following:

```output
Loop 1
Loop 2
Loop 3
Loop 4
Loop 5
```

The preceding code would print "forever" until you quit the program.

### Returning from a loop

It's possible to return a value from a loop as you exit it with a `break` statement.

Here's how you would write that:

```rust
let mut points = 0;
let result = loop {
    if points >= 10 {
        break points;
    }
    points += 2;
}
```

Here, `points` is incremented for each iteration. Once the break condition is true, the current value of `points` is returned back `break points` and the value is assigned to `result`.

## While

You've seen so far how you can use `loop` and define conditions inside of it and call `break` to exit the loop. With `while`, you can define the break condition as part of defining the `while`, like so:

```rust
let mut points = 0;
while points < 10 {
    points += 2;
}
println!("Value of points is {}", points);
```

Here, your break condition is defined right after the `while` keyword. There's no need to use an `if` or `break` keyword to quit the loop.

> Which version is easiest to read, `loop` or `while` ?

## Iterate a collection

A common reason for wanting to repeat a statement is processing something that has the character of a sequence. It could for example be:

- a list of points awarded in a swim competition
- a set of items in shopping basket

To define a list, we can use the following syntax:

```rust
let judges_result = [8, 7, 8, 9, 9];
```

To list a specific items in a list, we use the square brackets, `[]` and a number between 0 and the length of the list -1. In the above example, 0,1,2,3,4 are addressable indexes. Here's an example:

```rust
judges_result[2]; //8 
```

Trying to access with index 5, would cause an error. 

### Iteration

So how do we iterate through `iterates_result`? There are two approaches we could use:

- `while`, it's perfectly fine to use a `while`, however, we need to keep track on when to stop iterating as we can end up out of bounds.
- `for in`. With this construct, we are guarenteed to only list items for as long as there are items in the list.

Lets try the first variant with while:

```rust
let judges_result = [8, 7, 8, 9, 9];
let mut index = 0;
while index < 5 {
  println!("Judge: {0} is {1} ", index + 1, judges_result[index]);
}
```

Now, lets compare it to using `for in`:

```rust
let judges_result = [8, 7, 8, 9, 9];
for vote in &judges_result {
  println!("Judge: {} ", vote);
}
```

> Wait, that's not a fair comparison, what happened to the index ?

To get the index, we need to use a slightly more complex construct:

```rust
for (i, vote) in judges_result.iter().enumerate() {
     println!("Judge: {0} is {1} ", index + 1, vote);
}
```

What's happening here is that we call `iter()`, followed by calling `enumerate()`. Now we have access to a tuple that contains both the index, `i` and our value, `vote`. 

> REMINDER: a tuple is complex data type created by adding a parenthesis and comma separate values, like so:

  ```rust
  fn create_tuple(a: i32, b: i32) -> (i32, i32) {
      (a, b)
  }
  let (a,b) = create_tuple(2, 4);
  println!("{0} {1}", a, b);
  ```

## Assignment

Imagine someone read today's entries from a POS (Point of Sale system) from a CSV file into an array `entries`. Now print out out the total and the average value of a purchase.

> INFO: if there's a value in there below 0, it should be thrown a way, as it's an error when reading input.

Here's what running the program can look like:

```output
Here's today's purchases:
33.5, 7.25, 15.5, 44.9
The total is: 101.15
The average purchase was: 25.2875
```

## Solution

```rust
fn main () {
    let entries = [33.5, 7.25, 15.5, 44.9, -1.0];
    let mut total:f32 = 0.0;
    let mut approved_entries = 0;
    println!("Today's entries are");
    for item in entries {
        if item < 0 as f32 {
            continue;
        }
        total += item;
        print!("{},", item);
        approved_entries += 1; 
    }
    print!("\n");
    println!("The total is {}", total);
    println!("The average purchase was {}", total / approved_entries as f32);
}
```