Learning Rust 🦀: 03- The basics: Functions
Tags: learning, rust, programming, development
Published: 2023-06-08 16:45:55

I'll continue my Rust Learning Series and this time I'll continue talking about the basics, more specifically, functions. But first, I'd like to bring up a very good VS Code extension to work with Rust, the "_rust-analyzer_"

>#### ⚠️ Remember!
You can find all the code snippets for this series in its [accompanying repo](https://github.com/FadyGrAb/rust-learning-series)  
If you don't want to install Rust locally, you can play with all the code of this series in the official [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021) that can be found on its official page. (cargo commands won't run though. But you mostly won't be needing it)
⚠️⚠️ The articles in this series are loosely following the contents of "The Rust Programming Language, 2nd Edition" by Steve Klabnik and Carol Nichols in a way that reflects my understanding from a Python developer's perspective.

⭐ I try to publish a new article every week (maybe more if the Rust gods 🙌 are generous 😁) so stay tuned 😉. I'll be posting "new articles updates" on [my LinkedIn](https://www.linkedin.com/in/fady-abdelmassih).

### Table of Content
- [The rust analyzer VS Code extension](#the-rustanalyzer-vs-code-extension)
- [Functions](#functions)
    - [Parameters](#parameters)
    - [Statements and Expressions](#statements-and-expressions)
    - [Return Values](#return-values)

### The rust-analyzer VS Code extension:
Rust is hard to learn, I get it. But the good news is that there are tools out there that can make it easier! 😉
If you are using VS Code, [rust-analyser](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) is a wonderful companion to your Rust learning journey 👌. I highly recommend installing this extension while learning Rust (and when you are done learning too). As listed in its manual, rust-analyzer "is a library for semantic analysis of Rust code as it changes over time." Think of it as your Rust peer developer that has your good Rust coding form in heart 🥰. It can do a lot of stuff, like:
- Code completion with imports insertion
- Go to definition, implementation, type definition
- Find all references, workspace symbol search, symbol renaming
- Types and documentation on hover
- Inlay hints for types and parameter names
- Semantic syntax highlighting
- A lot of assists (code actions)
- Apply suggestions from errors
- And many more...

Highly recommended 👌

### Functions:
You may not know it, but you know how to define a function in Rust by now 😊. Remember the `main` function?!
Function in Rust are defined with the `fn` keyword. Like Python, functions can be called from other functions:
```rust
fn main() {
    println!("Main Function");
    // A function call
    second_function();

fn second_function() {
    println!("Second Function");
}
```
Here, we called `second_function` from the main function and the output should be like this:
```bash
Compiling functions v0.1.0 (/mnt/c/Users/fady/code/03-the-basics-functions-and-flow-control/functions)
    Finished dev [unoptimized + debuginfo] target(s) in 1.17s
     Running `target/debug/functions`
Main Function
Second Function
```
#### Parameters:
Like other languages, functions in rust accept `parameters`, `arguments` or whatever what you call the values passed to it 🤷‍♂️. But in Rust, parameters must have a defined type to eliminate the guess work for the Rust compiler. 
```rust
fn main() {
    // A function with parameters
    print_temperature(35, 'C');
}
fn print_temperature(value: i32, unit: char) {
    println!("The temperature is {value}{unit}");
}
```
The output this time will be:
```bash
The temperature is 35C
```
#### Statements and Expressions:
While in Python land, I didn't even bother to know the distinction between statements and expressions, who cares?! 😁
But in Rust, you have to know the difference and you will see why in the next section.
In short, "_Statements_" don't return a value and "_Expressions_" do and you can turn any expression into a statement by terminating it with a semi-colon ";", that's it! 😉
(Technically, statements return the "unit" aka THE VOID 😯)  
Here is an example:
```rust
fn main() {
    // Statements and Expressions
    // let y = (let z = 10); // Error: expected expression, found statement
    let x = 10; // Statement
    println!("The values of x is {x}");

    let y = {
        let z = 10;
        z + 13
    }; // The whole block is an expression
    println!("The value of y is {y}");
}
```
The `let` statement is a classic example of a Rust ... well ... statement 😁. It doesn't return anything. So the following would error out `let y = (let z = 10);` as `(let z = 10)` is a statement and you can't assign statements to statements! This makes my brain hurt 🤕!
For `y`, notice the absence of the semi-colon ";" after `z + 13` in the block. This (as we will see next) is the return value of the block and the whole block becomes an expression as it produces a "value". When you execute this code, you will see that the value of y is `23`. 

#### Return values:
You've probably guessed it from the previous section 😉. Functions can have explicit return value which is the "last expression in the function block". But like parameters, you must define the type of the function's return value. We use a similar syntax to Python's "type hinting". To define the return's value type, we use `->` then the desired type.
Here is an example:
```rust
fn main() {
    //Return Values
    let number_five = five();
    println!("number_five's value is {number_five}");

    let add_one = add_one(7);
    println!("The value of add_one is {add_one}")
}
fn five() -> u8 {
    5
}

fn add_one(value: i32) -> i32 {
    // value + 1; // Error (notice the semi-colon). The function is expecting a i32 return type but got unit ()
    value + 1
}
```
For the `five()` function, we return the number `5` (notice the absence of the semi-colon which makes this an expression). `5` can be safely casted into an "8-bits unsigned integer" type, hence the `-> u8` after the parentheses. If we rewrite the `five()` function as the following, it will error out:
```rust
fn five() -> u8 {
    5; // adding a semi-colon.
}
```
Here we are telling the Rust compiler that we are expecting an "8-bit unsigned integer" but the semi-colon transformed the last expression in the function's block into a statement, hence this function now returns "the unit ()".

That's a quick overview on Functions in Rust! In the next article, we will continue our discussion about flow control (if statement and loops). See you then 👋