Functions

Named functions

  • Named functions are declared with the keyword fn
  • When using arguments, you must declare the data types.
  • By default, functions return an empty tuple/ (). If you want to return a value, the return type must be specified after ->

i. Hello world

fn main() {
    println!("Hello, world!");
}

ii. Passing arguments

fn print_sum(a: i8, b: i8) {
    println!("sum is: {}", a + b);
}

iii. Returning values

// 01. Without the return keyword. Only the last expression returns.
fn plus_one(a: i32) -> i32 {
    a + 1
    // There is no ending ; in the above line.
    // It means this is an expression which equals to `return a + 1;`.
}
// 02. With the return keyword.
fn plus_two(a: i32) -> i32 {
    return a + 2;
    // Should use return keyword only on conditional/ early returns.
    // Using return keyword in the last expression is a bad practice.
}

iv. Function pointers, Usage as a Data Type

fn main() {
    // 01. Without type declarations.
    let p1 = plus_one;
    let x = p1(5); // 6

    // 02. With type declarations.
    let p1: fn(i32) -> i32 = plus_one;
    let x = p1(5); // 6
}

fn plus_one(a: i32) -> i32 {
    a + 1
}

Closures

  • Also known as anonymous functions or lambda functions.
  • The data types of arguments and returns are optional ⃰ⁱᵛ.

Example with a named function, before using closures.

fn main() {
  let x = 2;
  println!("{}", get_square_value(x));
}

fn get_square_value(i: i32) -> i32 {
    i * i
}

i. With optional type declarations of input and return types

fn main() {
    let x = 2;
    let square = |i: i32| -> i32 { // Input parameters are passed inside | | and expression body is wrapped within { }
        i * i
    };
    println!("{}", square(x));
}

ii. Without type declarations of input and return types

fn main() {
    let x = 2;
    let square = |i| i * i; // { } are optional for single-lined closures
    println!("{}", square(x));
}

iii. With optional type declarations; Creating and calling together

fn main() {
    let x = 2;
    let x_square = |i: i32| -> i32 { i * i }(x); // { } are mandatory while creating and calling same time.
    println!("{}", x_square);
}

iv. Without optional type declarations; Creating and calling together

fn main() {
    let x = 2;
    let x_square = |i| -> i32 { i * i }(x); // ⭐️ The return type is mandatory.
    println!("{}", x_square);
}