Control Structures

Control structures allow programers to insturct computers how to behave when faced with certian conditions.

Common control structures include:

  • if statements
  • else statements
  • for loops
  • while loops

We can relate the logic of these control sturtures to situations that we encounter in our lives.

For example: I could be at the grocery store looking at a bag of chips and think to myself: "if I add this bag of chips to my cart, I will likely eat its entire contents before I get home and feel like trash for the rest of the night."

A program that executes that logic could look like this:


fn main(){ // declare main function
    let chips=true; // use let statement to exhibit my lack of self control
    if chips { // declare if statement with boolean condition
        println!("I ate the whole bag of chips and feel like trash") // print result if true
    } // close if expression
} // close main function expression

Else statements tell the computer to do an action if the first condition is not met.

Using the first example, we can create an if-else control structure that runs code when the first condition is not true:


fn main(){ // declare main function
    let chips=false; // use let statement to exhibit my outstanding self control
    if chips { // declare if statement with boolean condition
        println!("I ate the whole bag of chips and feel like trash") // print result if true
    } else { // close if expression
        println!("Good work, idiot. You practiced self control!") // print supportive message
    } // close else expression
} // close main function expression

We can combine let and if statements. These statements might be useful when there are variables in our code that are condition-dependent. For example, after I finish a swim workout, my body looks gorgeous. However, on days when I don't swim, my body looks like a bony meat bag. A program that executes that logic could look like this:


fn main(){ // declare main function
    let swim=true; // declare boolen swim variable
    let gorgeous = if swim {["went for a swim", "gorgeous"]} else {["didn't for a swim", "like a bony meat bag"]}; // boolean let-if statement
    println!("Cassidy {}, and his body looks {}", gorgeous[0], gorgeous[1]); // print result of let-if statement
} // close main expression

The rust compiler expects let-if epressions to produce the same data types. For example, the program below evaluates boolean conditions and outputs what people might call Toronto based on a pre-defined age.


fn main() {
    let age=28; // create variable using let statement and boolean true 
    let toronto = if age <= 26 {"6"} else if age > 26 && age < 86 {"Tdot"} else {"The Big Smoke"}; // declare let-if statement with expressions 
    println!("My age is {age} and I call Toronto {toronto}", age=age.to_string(), toronto=toronto)
}

Below, we change the expression data type for the people who refer to Toronto as "The Six." Becasue we changed the output data type of this expression, the compiler returns an error.


fn main() {
    let age=28; // create integer variable using let statement  
    let toronto = if age <= 26 {6} else if age > 26 && age < 86 {"Tdot"} else {"The Big Smoke"}; // declare let-if statement with expressions 
    println!("My age is {age} and I call Toronto {toronto}", age=age.to_string(), toronto=toronto)
}

Loops allow us to do stuff fast. Rust has three loop types: for, loop, and while.

For loops run for perscribed iterations. In the example below, I created an array filled with events from a rec-league hockey game in which a player on the other team punched me, cowered behind the ref after I confronted him, and his teammate tried to intimidate the smallest player on our team. The for loop runs through the elements in the array, and the println! macro outputs each event with an intenisty integer. The intensity integers increase exponentially.


fn main() {
    let mut intensity = 0; // declare mutable variable using a let statement 
    let problems: [&str; 5] = ["A guy punched me", "The guy who punched me skated away after I confronted him", "The guy who punched me whined to the ref after he skated away", "The guy who punched me was too scared to look at me for the rest of the game", "The 220 lb teammate of the guy who punched me tried to intimidate the smallest player on our team"]; // declare array of problems, and specify data type and length 
    for problem in problems { // for loop that iterates through elements in array 
        if intensity < 2 { // boolean check until multiplication can represent exponential growth
            intensity += 1; // increment intensity 
        } else { // if intensity is greater than 2, the following expression can use multiplication to represent exponential growth
            intensity = intensity * intensity // multiply intensity by itself and redefine variable 
        }
        println!("{problem}. The intensity is now {intensity}", problem=problem, intensity=intensity.to_string()) // print current intensity
    } // close for loop 
} 

Loop loops run until they're told to stop. For example, a program could contain a boolean-if statement that checks for the number of iterations the program has completed. If the number of iterations triggers a true response from the if-expression, the programmer can use a break statement to end the loop.


fn main() { // create main function 
   let mut loops: u8 = 0; // assign mutable, unsiged, eight-bit integer to variable using let statement
   loop { // open loop expression
    if loops < 10 { // boolean check if current loop is less than ten 
        loops+=1; // increment loop number 
        println!("Loop number {}", loops); // print number of loops 
    } else { // boolean else
        break // break out of loop if current iteration is >= 10 
    }; // close else expression 
   }; // close loop expression 
} // close main function 

While loops run while a boolean condition is true. For example a while loop may run until an element in an array is found.


fn main() { // open main expression 
    let characteristics: [&str; 4] = ["Saquon Barkley", "Cassidy MacDonald", "got dem quads",  "got that dog in him"]; // declare array of static strings
    let mut i: usize = 0; // declare mutable index counter using usize type 
    while characteristics[i] != "got dem quads" { // while loop that iterates through elements in array 
       println!("{} {}", characteristics[i], characteristics[2]); // print the facts 
       println!("{} {}", characteristics[i], characteristics[3]); // print the facts 
       i+=1; // increment counter
        }; // close while loop 
    } // close main expression

Break and continue statements allow us to control loops. Break statements end loops and continue makes the program move on to the next iteration. For example, if you were playing monopoly with a resonable person and they caught you cheating, you may let them pass go before continuing the game. An un reasonable person, in contrast, may throw a temper tantrum and break the game. A program that demonstrates that scenario follows:


fn main() {
    // open main expression
    let cheating: [bool; 7] = [true, false, true, false, true, false, true]; // declare array of events
    let reasonable: [bool; 7] = [true, false, false, false, true, false, true]; // declare array of events
    let mut i: usize = 0; // declare index pointer
    for cheat in cheating { // open for loop that iterates through boolean array
        if reasonable[i] & cheat { // boolean if statement that checks if the players are reasonable and cheating
            println!("Pass go"); // print outcome
            i += 1; // increment counter 
            continue; // continue 
        } else if !reasonable[i] & cheat { // boolean if that checks if the players are not reasonable and cheating
            println!("Break that shit, King Kong"); // print outcome
            break; // Asshole broke the game
        }; // close expression
        i += 1; // increment counter if both conditions are not true
    } // close loop expression
} // close main expression 


Break and control statements can also be associated with specific loops. For example, you could use this if you had two arrays of names and to check if there were name duplicates.


fn main() {
    // open main expression
    let names_1: [&str; 4] = ["Fred", "Cocco", "Sally-Anne", "Ron"]; // declare array of names
     let names_2: [&str; 4] = ["Judy", "George", "Cocco", "Jen"]; // declare array of names
    'list_1: for name_1 in names_1 { // open for loop that iterates through names_1 array
        for name_2 in names_2 { // open second for loop that iterates through second array 
            if name_2 == name_1 { // boolean check to see if there are duplicate names
                println!("{name_1} is in array one and {name_2} is in array two", name_1=name_1, name_2=name_2); // print result if match 
                break 'list_1 // break out of outer loop
            } // close if expression
        } // close inner loop expression 
    } // close outer loop expression 
} // close main expression