Apps Artificial Intelligence CSS DevOps Go JavaScript Laravel Linux MongoDB MySQL PHP Python Rust Svelte Vue

Using Functions in Rust

2 min read .
Using Functions in Rust

Functions are reusable blocks of code that help divide a program into smaller, focused pieces. Rust functions can accept typed parameters, return values, borrow data, and work with functions or closures as inputs.

What Is a Function in Rust?

Functions are declared with the fn keyword, followed by the function name, parameters, an optional return type, and a body:

fn function_name(parameters) {
    // function body
}

Define and Call a Function

fn main() {
    greet();
}

fn greet() {
    println!("Hello, Rustacean!");
}

Rust does not require a function to be defined before the call site in the source file, as long as it is visible in the current module.

Function Parameters

Parameter types are written explicitly:

fn main() {
    add(5, 10);
}

fn add(a: i32, b: i32) {
    let sum = a + b;
    println!("Sum: {}", sum);
}

Here a and b are both i32 values.

Return Values

Write the return type after ->. Rust commonly returns the final expression of a function without a semicolon:

fn main() {
    let result = multiply(4, 5);
    println!("Product: {}", result);
}

fn multiply(x: i32, y: i32) -> i32 {
    x * y
}

You can also use an explicit return, which is especially useful for early exits.

Return Multiple Values with a Tuple

A tuple can package several return values:

fn main() {
    let (sum, product) = calculate(3, 7);
    println!("Sum: {}, Product: {}", sum, product);
}

fn calculate(a: i32, b: i32) -> (i32, i32) {
    (a + b, a * b)
}

For larger or domain-specific return values, a struct may communicate intent better than a tuple.

Borrow Values Instead of Moving Them

Pass a reference when a function only needs temporary access:

fn main() {
    let name = String::from("Alice");
    greet_name(&name);
    println!("Name after the function call: {}", name);
}

fn greet_name(name: &str) {
    println!("Hello, {}!", name);
}

Using &str makes the function accept both borrowed String values and string literals.

Functions and Closures

Functions can accept other callable values. If the API only needs a plain function pointer, use fn:

fn apply(a: i32, b: i32, func: fn(i32, i32) -> i32) -> i32 {
    func(a, b)
}

fn main() {
    let result = apply(3, 4, |x, y| x + y);
    println!("Result: {}", result);
}

For more flexible higher-order APIs, generic bounds such as Fn, FnMut, or FnOnce allow closures that capture values from their environment.

Best Practices

  1. Keep functions focused on one clear responsibility.
  2. Choose names that describe intent rather than implementation details.
  3. Prefer a struct or configuration type when a long parameter list represents one concept.
  4. Return Result or Option when failure or absence is part of normal control flow.
  5. Use references and slices when a function does not need ownership.
  6. Add Rustdoc comments (///) to public APIs when their purpose or contract is not obvious from the signature.

Conclusion

Functions are the basic building blocks of modular Rust programs. Typed parameters, expression-based returns, borrowing, tuples, and closure traits give you a broad set of tools for designing functions that are clear about data ownership and behavior.

Related Posts

chevron-up