Conditional Expressions and Flow Control in Rust

About This Module

This module covers Rust's conditional expressions, including if statements, if expressions, and the unique ways Rust handles control flow. Understanding these concepts is fundamental for writing effective Rust programs and leveraging Rust's expression-based syntax.

Prework

Prework Readings

Read the following sections from "The Rust Programming Language" book:

Pre-lecture Reflections

Before class, consider these questions:

  1. What is the difference between statements and expressions in programming?
  2. How might expression-based syntax improve code readability and safety?
  3. What are the advantages of mandatory braces in conditional statements?
  4. How do different languages handle ternary operations?
  5. What role does type consistency play in conditional expressions?

Learning Objectives

By the end of this module, you should be able to:

  • Use if statements for conditional execution
  • Leverage if expressions to assign values conditionally
  • Understand Rust's expression-based syntax
  • Apply proper type consistency in conditional expressions
  • Write clean, readable conditional code following Rust conventions
  • Understand the differences between Rust and other languages' conditional syntax

An Aside -- Approach to Learning New Languages

Systematic Language Learning Framework:

When learning any new programming language, consider these key areas:

  1. Data Types: What types of variables and data structures are available?
  2. Functions: What is the syntax for defining and calling functions?
  3. Build System: How do you compile and run code?
  4. Control Flow: Syntax for conditionals, loops, and branching
  5. Code Organization: How to structure programs (structs, modules, etc.)
  6. Language-Specific Features: Unique aspects of the language
  7. Additional Considerations: I/O, external libraries, ecosystem

Basic if Statements

Syntax:

if condition {
    DO-SOMETHING-HERE
} else {
    DO-SOMETHING-ELSE-HERE
}
  • else part optional
  • Compared to many C-like languages:
    • no parentheses around condition needed!
    • the braces mandatory

Example of if

Simple if statement.

fn main() {
    let x = 7;

    if x <= 15 {
        println!("x is not greater than 15");
    }
}
  • parentheses optional around condition -- try it with!
  • no semicolon after the if braces
fn main() {
    let threshold = 5;
    if x <= threshold {
        println!("x is at most {}",threshold);
    } else {
        println!("x is greater than {}", threshold);
    }
}

Using conditional expressions as values

In Python:

result = 100 if (x == 7) else 200 

C++:

result = (x == 7) ? 100 : 200

Rust:

fn main() {
    let x = 4;
    let result = if x == 7 {100} else {200};
    println!("{}",result);
}
fn main() {
// won't work: same type needed
    let x = 4;
    println!("{}",if x == 7 {100} else {1.2});
}
  • blocks can be more complicated
  • last expression counts (no semicolon after)
  • But please don't write this just because you can
#![allow(unused)]
fn main() {
let x = 4;
let z = if x == 4 {
    let t = x * x;
    t + 1
} else {
    x + 1
};
println!("{}",z);
}

Write this instead:

#![allow(unused)]
fn main() {
let x = 4;
let z;
if x == 4 { z = x*x+1 } else { z = x+1};
println!("{}", z)
}

Obscure Code Competition Winner

A winner of the most obscure code competition (https://www.ioccc.org/)

What does this program do?

#include <stdio.h> 

#define N(a)       "%"#a"$hhn"
#define O(a,b)     "%10$"#a"d"N(b)
#define U          "%10$.*37$d"
#define G(a)       "%"#a"$s"
#define H(a,b)     G(a)G(b)
#define T(a)       a a 
#define s(a)       T(a)T(a)
#define A(a)       s(a)T(a)a
#define n(a)       A(a)a
#define D(a)       n(a)A(a)
#define C(a)       D(a)a
#define R          C(C(N(12)G(12)))
#define o(a,b,c)   C(H(a,a))D(G(a))C(H(b,b)G(b))n(G(b))O(32,c)R
#define SS         O(78,55)R "\n\033[2J\n%26$s";
#define E(a,b,c,d) H(a,b)G(c)O(253,11)R G(11)O(255,11)R H(11,d)N(d)O(253,35)R
#define S(a,b)     O(254,11)H(a,b)N(68)R G(68)O(255,68)N(12)H(12,68)G(67)N(67)

char* fmt = O(10,39)N(40)N(41)N(42)N(43)N(66)N(69)N(24)O(22,65)O(5,70)O(8,44)N(
            45)N(46)N    (47)N(48)N(    49)N( 50)N(     51)N(52)N(53    )O( 28,
            54)O(5,        55) O(2,    56)O(3,57)O(      4,58 )O(13,    73)O(4,
            71 )N(   72)O   (20,59    )N(60)N(61)N(       62)N (63)N    (64)R R
            E(1,2,   3,13   )E(4,    5,6,13)E(7,8,9        ,13)E(1,4    ,7,13)E
            (2,5,8,        13)E(    3,6,9,13)E(1,5,         9,13)E(3    ,5,7,13
            )E(14,15,    16,23)    E(17,18,19,23)E(          20, 21,    22,23)E
            (14,17,20,23)E(15,    18,21,23)E(16,19,    22     ,23)E(    14, 18,
            22,23)E(16,18,20,    23)R U O(255 ,38)R    G (     38)O(    255,36)
            R H(13,23)O(255,    11)R H(11,36) O(254    ,36)     R G(    36 ) O(
            255,36)R S(1,14    )S(2,15)S(3, 16)S(4,    17 )S     (5,    18)S(6,
            19)S(7,20)S(8,    21)S(9    ,22)H(13,23    )H(36,     67    )N(11)R
            G(11)""O(255,    25 )R        s(C(G(11)    ))n (G(          11) )G(
            11)N(54)R C(    "aa")   s(A(   G(25)))T    (G(25))N         (69)R o
            (14,1,26)o(    15, 2,   27)o   (16,3,28    )o( 17,4,        29)o(18
            ,5,30)o(19    ,6,31)o(        20,7,32)o    (21,8,33)o       (22 ,9,
            34)n(C(U)    )N( 68)R H(    36,13)G(23)    N(11)R C(D(      G(11)))
            D(G(11))G(68)N(68)R G(68)O(49,35)R H(13,23)G(67)N(11)R C(H(11,11)G(
            11))A(G(11))C(H(36,36)G(36))s(G(36))O(32,58)R C(D(G(36)))A(G(36))SS

#define arg d+6,d+8,d+10,d+12,d+14,d+16,d+18,d+20,d+22,0,d+46,d+52,d+48,d+24,d\
            +26,d+28,d+30,d+32,d+34,d+36,d+38,d+40,d+50,(scanf(d+126,d+4),d+(6\
            -2)+18*(1-d[2]%2)+d[4]*2),d,d+66,d+68,d+70, d+78,d+80,d+82,d+90,d+\
            92,d+94,d+97,d+54,d[2],d+2,d+71,d+77,d+83,d+89,d+95,d+72,d+73,d+74\
            ,d+75,d+76,d+84,d+85,d+86,d+87,d+88,d+100,d+101,d+96,d+102,d+99,d+\
            67,d+69,d+79,d+81,d+91,d+93,d+98,d+103,d+58,d+60,d+98,d+126,d+127,\
            d+128,d+129

char d[538] = {1,0,10,0,10};

int main() {
    while(*d) printf(fmt, arg);
}

Best Practices

Formatting and Style:

  1. Use consistent indentation (4 spaces)
  2. Keep conditions readable - use parentheses for clarity when needed
  3. Prefer early returns in functions to reduce nesting
  4. Use else if for multiple conditions rather than nested if

Example of Good Style:

fn classify_temperature(temp: f64) -> &'static str {
    if temp > 30.0 {
        "Hot"
    } else if temp > 20.0 {
        "Warm"
    } else if temp > 10.0 {
        "Cool"
    } else {
        "Cold"
    }
}

fn main() {
    println!("{}", classify_temperature(35.0));
    println!("{}", classify_temperature(25.0));
    println!("{}", classify_temperature(15.0));
    println!("{}", classify_temperature(5.0));
}

Exercise

Write a function that takes a number and returns a string that says whether it is positive, negative, or zero.

Example output:

10 is positive
-5 is negative
0 is zero
// Your code here