Rust: Control Flow

Rust: Control Flow

Learn Rust control flow statements with ChatGPT

ยท

7 min read

In structured programming, control flow statements are used to specify the order in which a program's instructions should be executed. There are three types of control flow statements in structured programming:

  1. Sequential: This type of control flow executes instructions one after the other, in the order they are written in the program.

  2. Decision: This type of control flow allows the program to execute different instructions based on whether one or more conditions are true or false.

  3. Iteration: This type of control flow allows the program to repeat a set of instructions multiple times, as long as a certain condition is true.

  4. Selection: This type of control flow allows the program to execute different instructions based on a value of a control variable or expression that is not necesarly boolean.

Implementation

In Rust, there are several control flow statements that are used to implement each of these types of control flow. Here are some examples:

Sequential

To execute instructions in Rust in the order they are written, you can simply write the instructions one after the other. For example:

   println!("Hello");
   println!("World");

This code will output "Hello" followed by "World" in the console.

Decision

Decision statement is consist in one Boolean expression that can control execution of one or more statements. We use two design patterns. One that is usually called "decision branching" and a second one that is called "decision ladder". Here are two examples:

Syntax:

Rust provides an if statement for selection control flow. The structure of the if statement is:

   if condition {
       // code to execute if condition is true
   } else {
       // code to execute if condition is false
   }

Branching:

In computer science, decision branching refers to the process of controlling the flow of a program based on a decision made during runtime. It is a fundamental concept in programming that helps to make the code more flexible and dynamic.

   let number = 6;

   if number % 2 == 0 {
       println!("The number is even");
   } else {
       println!("The number is odd");
   }

This code will check if number is even or odd, and output the corresponding message in the console.

Ladder

In computer science, a decision ladder refers to a conditional flow of execution where a decision is made at each step based on the input or current state of the program. This is usually achieved using control structures such as if/else statements or switch statements.

Here's a basic example of a decision ladder in Rust using an if/else statement:

fn main() {
    let number = 10;

    if number < 5 {
        println!("Number is less than 5");
    } else if number < 10 {
        println!("Number is between 5 and 9");
    } else {
        println!("Number is greater than or equal to 10");
    }
}

In this example, the variable number is assigned a value of 10. The program then evaluates the value of number using a series of conditional statements. The first if statement checks whether number is less than 5, which is false in this case. The next else if statement checks whether number is less than 10, which is also false, so the program proceeds to the else block and prints the message "Number is greater than or equal to 10".

This is a simple example, but decision ladders are used in more complex programs to handle a wide variety of situations based on the input or state of the program.

Iteration

Rust provides several looping constructs for iteration control flow. One of the most common ones is the for loop, which is used to loop over a range of values.

The structure of the for loop is:

   for variable in range {
       // code to execute for each value in range
   }

For example:

   for i in 1..4 {
       println!("The value of i is {}", i);
   }

This code will output the value of i for each iteration of the loop.

Another looping construct available in Rust is the while loop, which is used to repeat a block of code as long as a certain condition is true. The structure of the while loop is:

   while condition {
       // code to execute while condition is true
   }

For example:

   let mut count = 0;

   while count < 5 {
       println!("Count is {}", count);
       count += 1;
   }

This code will output the value of count for each iteration of the loop, as long as count is less than 5.

Selection

Selection is done in Rust used for pattern matching. You can use keyword "match" to create this statement. The structure of the match statement is similar to the switch statement in other programming languages. It allows you to compare a value against a set of patterns, and then execute the corresponding code block for the matching pattern.

Example

Here is an example to illustrate the use of match control flow in Rust:

   let number = 7;

   match number {
       0 => println!("The number is zero"),
       1 | 2 => println!("The number is a small prime"),
       3..=7 => println!("The number is a medium prime"),
       _ => println!("The number is not a small or medium prime")
   };

In this example, we have defined a variable number and used a match control flow block to determine what type of number it is. The match statement matches the value of number against a set of patterns:

  • If number is 0, it will execute println!("The number is zero")

  • If number is 1 or 2, it will execute println!("The number is a small prime")

  • If number is between 3 and 7 (inclusive), it will execute println!("The number is a medium prime")

  • If number does not match any of the above patterns, it will execute println!("The number is not a small or medium prime")

In this way, we can use match to handle complex control flows based on pattern matching in Rust.


CLI Example

Rust CLI app that asks 10 questions related to Rust with yes/no answers:

use std::io::{self, Write};

fn main() {
    println!("Welcome to the Rust Quiz!");
    let mut correct_answers = 0;

    let questions = [
        "Rust is a statically typed language. (y/n)",
        "Rust is suitable for safe concurrent. (y/n)",
        "Rust is a garbage-collected language. (y/n)",
        "Rust is compatible with C ABI. (y/n)",
        "Rust doesn't allow null pointers. (y/n)",
        "Rust has an equivalent of a C++ template. (y/n)",
        "Rust has a built-in unit testing. (y/n)",
        "Rust's package manager is called cargo. (y/n)",
        "Rust has its own package registry. (y/n)",
        "Rust use versioned-rustc for stable syntax. (y/n)",
    ];

    let answers = ["y", "y", "n", "y", "y", "y", "y", "y", "y", "y"];

    // Loop through the questions and get the user's input
    for (i, &question) in questions.iter().enumerate() {
        print!("{}: ", question);
        io::stdout().flush().unwrap();
        let mut input = String::new();
        io::stdin()
            .read_line(&mut input)
            .expect("Failed to read input");
        let answer = input.trim();
        // Check if the answer is correct and increment
        if answer == answers[i] {
            correct_answers += 1;
        }
    }

    let score = correct_answers as f64 / questions.len() as f64 * 100.0;
    let grade = match score {
        70.0..=100.0 => "A",
        60.0..=69.0 => "B",
        50.0..=59.0 => "C",
        _ => "D/F",
    };

    if grade == "D/F" {
        println!("\nQuiz failed! You scored {:.2}%. Better luck next time.", score);
    } else {
        println!("\nQuiz passed with grade {}: {:.2}% correct answers!", grade, score);
        println!("Congratulations!");
    }
}

In this example, the program first displays a welcome message and then asks the user 10 questions about Rust. After each question, the program compares the user's answer with the correct answer stored in an array called answers. If the answer is correct, the correct_answers counter is increased.

After all the questions have been answered, the program calculates the user's score and converts it to a grade based on the following criteria:

  • A: 70% or higher

  • B: 60% - 69%

  • C: 50% - 59%

  • D/F: less than 50%

Finally, the program prints out the user's final score and grade, along with a congratulatory message if the user passed the quiz.

In this version, the match expression is used to convert the user's score to a grade. The ..= syntax is used to specify a range of values for each grade, and the _ pattern is used as a catch-all for any score that doesn't fall into the specified ranges.

You can run this app here: ChatGOTQuiz


Conclusion:

Overall, while control flow statements in Turing complete languages like assembly are limited, hybrid languages like Rust offer powerful and expressive control flow constructs. And while functional languages may offer more limited control flow capabilities than hybrid languages, they make up for it in other areas, such as being more expressive and having better support for concurrency and parallelism.


Disclaimer: This article was created with the help of ChatGPT, a large language model. However, I have modified the response, including my own opinions and thoughts. Therefore, this article is a hybrid of ChatGPT's output and my own input. If you do not agree with something I have said, please feel free to comment below and we can discuss it further.


Thanks for reading. Learn fast and prosper ๐Ÿ€๐Ÿ––๐Ÿผ

ย