<jupyter_start><jupyter_text>Rust Crash Course - 02 - Functions and Control FlowFunctions and control flow elements are essential to structure a program.In the following, the implementation of these concepts in Rust is explained.The contents represent a brief and compact introduction to the topic, inspired by the [Rust Book](https://doc.rust-lang.org/book/), the [Rust Reference](https://doc.rust-lang.org/reference/), and [Rust By Example](https://doc.rust-lang.org/rust-by-example/).  FunctionsThe ``main()`` function in Rust is the entry point for all programs. However, in the Jupyter kernel running these notebooks, the ``main()`` function is hidden and not explicitly visible. Nevertheless, functions can be defined by the keyword ``fn``, which is useful to structure code.Functions can be defined before or after the calling function, Rust does not care about that.As for variables, ``snake_case`` is the conventional style for function names.<jupyter_code>fn some_function() {
    println!("some function executing ...");

    special_function_snake_case();
}

fn special_function_snake_case() {
    println!("special function executing ...");
}

some_function();<jupyter_output><empty_output><jupyter_text>ArgumentsFunction arguments can be specified between the brackets after the function name.<jupyter_code>fn print_squared_value(mut value: u32, value_name: &str) {
    value = value * value;
    println!("{} (squared) = {}", value_name, value);
}

let mut x = 7;

print_squared_value(x, "Test Value");    // call by value, i.e. value copied to function

println!("x = {}", x);    // no squaring of original value<jupyter_output><empty_output><jupyter_text>Return ValuesIf a function should return a value, this is denoted by ``->`` followed by the data type of the return value.The last expression in the body of a function is automatically returned.Early or explicit return from a function is possible by using the keyword ``return``.<jupyter_code>fn add(a: u8, b: u8) -> u8 {
    a + b
}

fn sub(a: u8, b: u8) -> u8 {
    let c = a - b;
    return c
}

let a = 5;
let b = 3;
println!("a + b = {}", add(a, b));
println!("a - b = {}", sub(a, b));<jupyter_output><empty_output><jupyter_text>The following example results in a compile error, because the ``;`` in the last line of the function body changes the expression to a statement.<jupyter_code>fn add(a: u8, b: u8) -> u8 {
    a + b;
}

let a = 7;
let b = 8;
println!("a + b = {}", add(a, b));<jupyter_output><empty_output><jupyter_text>Control FlowThe most common control flow elements are conditional paths and loops.  ``if`` Expressions``if`` and ``else`` expressions allow to select one branch from different possible branches, depending on given conditions.<jupyter_code>let height = 117;

if height < 120 {
    println!("Stop! Height is too low!");
} else {
    println!("Go ahead ...");
};<jupyter_output><empty_output><jupyter_text>Further, it is possible to use ``else if`` constructs to check multiple conditions.<jupyter_code>let height = 156;

if height < 140 {
    println!("Size: S");
} else if height < 160 {
    println!("Size: M");
} else if height < 180 {
    println!("Size: L");
} else {
    println!("Size: XL");
};<jupyter_output><empty_output><jupyter_text>Also, ``if`` expressions can be used on the right side of ``let`` statements.<jupyter_code>let n_people = 11;
let n_tables = if n_people <= 8 {
    1
} else {
    2
};

println!("{} people need {} table(s)!", n_people, n_tables);<jupyter_output><empty_output><jupyter_text>``match`` ExpressionsThe ``match`` operator in Rust enables a variety of efficient programming constructs. It compares a given value to a series of patterns and executes code, depending on the first matching pattern. It is similar to ``switch`` statements in C, but more powerful.<jupyter_code>enum DayOfWeek {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday,
}

fn hours_in_office(day: DayOfWeek) -> u8 {
    match day {
        DayOfWeek::Monday => 8,
        DayOfWeek::Tuesday => 6,
        DayOfWeek::Wednesday => 10,
        DayOfWeek::Thursday => 5,
        DayOfWeek::Friday => 4,
        DayOfWeek::Saturday => {
            println!("IT'S WEEKEND, MAN!");
            0
        },
        DayOfWeek::Sunday => {
            println!("IT'S WEEKEND, MAN!");
            0
        },
    }
}

println!("On Tuesday, I spent {} hours in office!", hours_in_office(DayOfWeek::Tuesday));
println!("On Saturday, I spent {} hours in office!", hours_in_office(DayOfWeek::Saturday));<jupyter_output><empty_output><jupyter_text>Another important fact about ``match`` expressions is that they have to be exhaustive. If a code does not handle all possibilities, the compiler will show an error. However, there is a placeholder (``_``) that handles all remaining patterns.<jupyter_code>fn hours_of_freetime(day: DayOfWeek) -> u8 {
    match day {
        DayOfWeek::Saturday => 8,
        DayOfWeek::Sunday => 12,
        _ => 0,
    }
}

println!("On Tuesday, I have {} hours of freetime!", hours_of_freetime(DayOfWeek::Tuesday));<jupyter_output><empty_output><jupyter_text>Common use cases for ``match`` expressions are the ``Option`` and the ``Result`` data types, because easy handling of absent data and errors is possible.<jupyter_code>fn square(a: Option<i32>) -> Result<i32, &'static str> {
    match a {
        None    => Err("No number to square!"),
        Some(c) => Ok(c * c),
    }
}

fn print_number (a: Result<i32, &'static str>) {
    match a {
        Ok(n)  => println!("number = {}", n),
        Err(e) => println!("ERROR: {}", e),
    }
}

let squared_result = square(Some(17));
let squared_none = square(None);

println!("double_result = {:?}", squared_result);
println!("double_none = {:?}", squared_none);

print_number(squared_result);
print_number(squared_none);<jupyter_output><empty_output><jupyter_text>``loop`` LoopsThe ``loop`` keyword executes code in an endless loop until it is explicitly told to stop by the ``break`` keyword. Unlike other programming languages, a ``loop`` loop may return a value, but does not have to.<jupyter_code>let mut counter = 0;
let mut faculty = 1;

faculty = loop {
    counter += 1;
    faculty *= counter;
    if counter == 8 {
        break faculty;
    }
};

println!("Faculty of 8 is: {}", faculty);<jupyter_output><empty_output><jupyter_text>``while`` LoopsLoops that should run as long as a specific condition is ``true`` can be implemented using ``while`` loops.<jupyter_code>let mut number = 0;
let mut sum = 0;

while number < 6 {
    number += 1;
    sum += number;
};

println!("Sum of numbers up to 6 is: {}", sum);<jupyter_output><empty_output><jupyter_text>``for`` Loops``for`` loops are especially useful to loop through every element of an array or a collection.<jupyter_code>const TEMPERATURE_MAX: f32 = 40.0;

let temperature = [21.3, 22.7, 22.4, 25.2, 21.9];

for t in temperature.iter() {
    println!("Temperature {:.1} is {:.1} degrees from MAX!", t, TEMPERATURE_MAX - t);
    // {:.1} tells the formatter to display only one decimal place
};<jupyter_output><empty_output><jupyter_text>ExercisesThe following exercises may help to practice the obtained knowledge.  The Broken CodeThe following code is broken and cannot be compiled.Correct the code in order to compile and output the final position of the "runner" (x = -18, y = -7).<jupyter_code>enum Running {
    Right(i8),
    Left(i8),
    Forward(i8),
    Backward(i8),
}

let mut x_pos: i8 = 0
let mut y_pos: i8 = 0

let steps: [i8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

fn run(x, y, mv: Running) -> (i8, i8) {
    let x_new = match mv {
        Running::Right(n) => x + n,
        Running::Left(n) => x - n,
        Running::Forward(n) => x,
        Running::Backward(n) => x,
    };
    let y_new = match mv {
        Running:::Right(n) => y,
        Running:::Left(n) => y,
        Running:::Forward(n) => y + n,
        Running:::Backward(n) => y - n,
    }
    (x_new, y_new)
}

let mut counter = 0;

println("Runners starts at ({}, {})!", x_pos, y_pos);

while counter < 10 {
    let mut new_pos: (u32, u32) = (0, 0);
    if counter < 2 {
        new_pos = run(x_pos, y_pos, Running::Right(steps[counter]));
    } else if counter < 5 {
        new_pos = run(x_pos, y_pos, Running::Forward(steps(counter)));
    } else if counter < 8 {
        new_pos = run(x_pos, y_pos, Running::Left(steps[counter]));
    } else {
        new_pos = run(x_pos, y_pos, Running::Backward(steps[counter]));
    }
    x_pos = new_pos.0;
    y_pos = new_pos.1;
    println!("Runner is now at (x = {}, y = {})!"; x_pos, y_pos);
    counter += 1;
}

println!("Runner stopped its workout!");<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13778849466069584, 'fraction_numerical': 0.01584567688598002, 'mean_word_length': 3.8496659242761693, 'pattern_counts': {'":': 0, '<': 70, '<?xml version=': 0, '>': 90, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '158400', 'license': 'Apache-2.0', 'n_tokens_mistral': 2926, 'n_tokens_neox': 2788, 'n_words': 929, 'path': 'notebooks/Rust_Crash_Course_02_Functions_and_Control_Flow.ipynb', 'repo_name': 'htwg-syslab-pir/rust-crash-course-jupyter-notebooks', 'size': '8709'}