Syntax

Don't jump ahead!
Complete the exercise for the previous section before you start this one.
It's located in exercises/01_intro/00_welcome, in the course GitHub's repository.
Use wr to start the course and verify your solutions.

The previous task doesn't even qualify as an exercise, but it already exposed you to quite a bit of Rust syntax. We won't cover every single detail of Rust's syntax used in the previous exercise. Instead, we'll cover just enough to keep going without getting stuck in the details.
One step at a time!

Comments

You can use // for single-line comments:

#![allow(unused)]
fn main() {
// This is a single-line comment
// Followed by another single-line comment
}

Functions

Functions in Rust are defined using the fn keyword, followed by the function's name, its input parameters, and its return type. The function's body is enclosed in curly braces {}.

In previous exercise, you saw the greeting function:

#![allow(unused)]
fn main() {
// `fn` <function_name> ( <input params> ) -> <return_type> { <body> }
fn greeting() -> &'static str {
    // TODO: fix me πŸ‘‡
    "I'm ready to __!"
}
}

greeting has no input parameters and returns a reference to a string slice (&'static str).

Return type

The return type can be omitted from the signature if the function doesn't return anything (i.e. if it returns (), Rust's unit type). That's what happened with the test_welcome function:

#![allow(unused)]
fn main() {
fn test_welcome() {
    assert_eq!(greeting(), "I'm ready to learn Rust!");
}
}

The above is equivalent to:

#![allow(unused)]
fn main() {
// Spelling out the unit return type explicitly
//                   πŸ‘‡
fn test_welcome() -> () {
    assert_eq!(greeting(), "I'm ready to learn Rust!");
}
}

Returning values

The last expression in a function is implicitly returned:

#![allow(unused)]
fn main() {
fn greeting() -> &'static str {
    // This is the last expression in the function
    // Therefore its value is returned by `greeting`
    "I'm ready to learn Rust!"
}
}

You can also use the return keyword to return a value early:

#![allow(unused)]
fn main() {
fn greeting() -> &'static str {
    // Notice the semicolon at the end of the line!
    return "I'm ready to learn Rust!";
}
}

It is considered idiomatic to omit the return keyword when possible.

Input parameters

Input parameters are declared inside the parentheses () that follow the function's name.
Each parameter is declared with its name, followed by a colon :, followed by its type.

For example, the greet function below takes a name parameter of type &str (a "string slice"):

#![allow(unused)]
fn main() {
// An input parameter
//        πŸ‘‡
fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}
}

If there are multiple input parameters, they must be separated with commas.

Type annotations

Since we've been mentioned "types" a few times, let's state it clearly: Rust is a statically typed language.
Every single value in Rust has a type and that type must be known to the compiler at compile-time.

Types are a form of static analysis.
You can think of a type as a tag that the compiler attaches to every value in your program. Depending on the tag, the compiler can enforce different rulesβ€”e.g. you can't add a string to a number, but you can add two numbers together. If leveraged correctly, types can prevent whole classes of runtime bugs.

Exercise

The exercise for this section is located in 01_intro/01_syntax