2.7 Functions and Methods

Functions are defined using the fn keyword, followed by the function name, parameter list (with types), and an optional return type specified after ->.

2.7.1 Function Declaration and Return Values

// Function that takes two i32 parameters and returns an i32
fn add(a: i32, b: i32) -> i32 {
    // The last expression in a block is implicitly returned
    // if it doesn't end with a semicolon.
    a + b
}

// Function that takes no parameters and returns nothing (unit type `()`)
fn greet() {
    println!("Hello from the greet function!");
    // No return value needed, implicit `()` return
}

fn main() {
    let sum = add(5, 3);
    println!("5 + 3 = {}", sum);
    greet();
}

Key Points (Functions):

  • Parameter types must be explicitly annotated.
  • The return type is specified after ->. If omitted, the function returns the unit type ().
  • The value of the last expression in the function body is automatically returned, unless it ends with a semicolon (which turns it into a statement). The return keyword can be used for early returns.

2.7.2 Methods

In Rust, methods are similar to functions but are defined within impl blocks and are associated with a specific type (like a struct or enum). The first parameter of a method is usually self, &self, or &mut self, which refers to the instance the method is called on—similar to the implicit this pointer in C++.

Methods are called using dot notation: instance.method() and can be chained.

struct Point {
    x: i32,
    y: i32,
}

impl Point {
    // Method that calculates the distance from the origin
    fn magnitude(&self) -> f64 {
        // Calculate square of components, cast i32 to f64 for sqrt
        ((self.x.pow(2) + self.y.pow(2)) as f64).sqrt()
    }
}

fn main() {
    let p = Point { x: 3, y: 4 };
    println!("Distance from origin: {}", p.magnitude());
}

Key Points (Methods):

  • Methods are functions tied to a type and defined in impl blocks.
  • The first parameter is typically self, &self, or &mut self, representing the instance.
  • Methods are called using dot (.) syntax.
  • Methods without a self parameter (e.g., String::new()) are called associated functions. These are often used as constructors or for operations related to the type but not a specific instance.

2.7.3 Comparison with C

#include <stdio.h>

// Function declaration (prototype) often needed in C
int add(int a, int b);
void greet(void);

int main() {
    int sum = add(5, 3);
    printf("5 + 3 = %d\n", sum);
    greet();
    return 0;
}

// Function definition
int add(int a, int b) {
    return a + b; // Explicit return statement required
}

void greet(void) {
    printf("Hello from the greet function!\n");
    // No return statement needed for void functions
}
  • C often requires forward declarations (prototypes) if a function is called before its definition appears. Rust generally doesn’t need them within the same module.
  • C requires an explicit return statement for functions returning values. Rust allows implicit returns via the last expression.
  • C does not have a direct equivalent to methods; behavior associated with data is typically implemented using standalone functions that take a pointer to the data structure as an argument.