Functions

Functions in Rust use snake_case convention and require explicit type annotations for parameters (unlike TypeScript’s optional inference).

Filename: src/main.rs

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

    another_function();
}

fn another_function() {
    println!("Another function.");
}

Functions are defined with fn and can be declared in any order within scope. The compiler doesn’t care about declaration order, similar to hoisting in JavaScript.

Parameters

Unlike TypeScript, parameter types are mandatory:

Filename: src/main.rs

fn main() {
    another_function(5);
}

fn another_function(x: i32) {
    println!("The value of x is: {x}");
}

Multiple parameters:

Filename: src/main.rs

fn main() {
    print_labeled_measurement(5, 'h');
}

fn print_labeled_measurement(value: i32, unit_label: char) {
    println!("The measurement is: {value}{unit_label}");
}

Statements vs Expressions

Critical distinction for Rust (unlike TypeScript where nearly everything is an expression):

  • Statements: Perform actions, return no value (let y = 6;)
  • Expressions: Evaluate to values (5 + 6, function calls, blocks)
fn main() {
    let y = 6;
}

This won’t compile (unlike JavaScript/TypeScript):

Filename: src/main.rs

fn main() {
    let x = (let y = 6);
}

Blocks are expressions:

Filename: src/main.rs

fn main() {
    let y = {
        let x = 3;
        x + 1
    };

    println!("The value of y is: {y}");
}

The block evaluates to 4 because x + 1 lacks a semicolon. Adding a semicolon converts an expression to a statement.

Return Values

Return type annotation required after ->. Functions return the last expression implicitly (no return keyword needed):

Filename: src/main.rs

fn five() -> i32 {
    5
}

fn main() {
    let x = five();

    println!("The value of x is: {x}");
}

Parameter and return example:

Filename: src/main.rs

fn main() {
    let x = plus_one(5);

    println!("The value of x is: {x}");
}

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

Critical: Adding a semicolon to the return expression breaks the return:

Filename: src/main.rs

fn main() {
    let x = plus_one(5);

    println!("The value of x is: {x}");
}

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

This fails because statements return () (unit type), not the expected i32. The semicolon behavior is fundamentally different from TypeScript where semicolons are purely syntactic.