Rust - Functions
Functions in Rust are a fundamental building block of the language, used to encapsulate reusable code into distinct units. Here's a detailed overview of how to define and use functions in Rust:
Defining Functions
A function is defined using the fn
keyword, followed by the function name, parameters, and the
function body. The function's return type, if any, is specified after an arrow (->
).
Basic Function
rustfn main() {
greet(); // Calling the function
}
fn greet() {
println!("Hello, world!");
}
In this example, greet
is a function that prints a message to the console. It doesn’t take any
parameters and doesn’t return any value.
Functions with Parameters
Functions can take parameters, which are variables passed into the function.
Function with Parameters
rustfn main() {
let name = "Alice";
greet(name);
}
fn greet(name: &str) {
println!("Hello, {}!", name);
}
In this example, the greet
function takes a single parameter name
of type
&str
(string slice) and prints a personalized message.
Returning Values
Functions can return values using the ->
syntax. The return type comes after the
->
symbol.
Function Returning a Value
rustfn main() {
let result = add(5, 3);
println!("The sum is: {}", result);
}
fn add(a: i32, b: i32) -> i32 {
a + b // The return value is the result of this expression
}
In this example, the add
function returns the sum of two integers. Note that Rust functions return
the value of the last expression in the function body by default, without needing a return
keyword.
Early Return
You can use the return
keyword to return a value early from a function.
rustfn main() {
let result = factorial(5);
println!("Factorial: {}", result);
}
fn factorial(n: u32) -> u32 {
if n == 0 {
return 1;
}
n * factorial(n - 1)
}
Function Overloading
Rust does not support function overloading (multiple functions with the same name but different parameters). You must use different names for different functions.
Functions as First-Class Citizens
In Rust, functions can be passed as arguments to other functions, returned from functions, and assigned to variables. They are first-class citizens.
Function as a Parameter
rustfn main() {
let result = operate(3, 4, add);
println!("Result: {}", result);
}
fn add(x: i32, y: i32) -> i32 {
x + y
}
fn operate<F>(x: i32, y: i32, func: F) -> i32
where
F: Fn(i32, i32) -> i32,
{
func(x, y)
}
In this example, operate
takes a function func
as a parameter and calls it.
Closures
Closures are anonymous functions that can capture their environment. They are defined using ||
syntax.
Basic Closure
rustfn main() {
let add = |a: i32, b: i32| -> i32 { a + b };
let result = add(5, 3);
println!("The sum is: {}", result);
}
Function Signatures and Type Annotations
You can specify the types of parameters and return values explicitly in function signatures. Rust's strong type system ensures type safety.
Function with Type Annotations
rustfn multiply(x: f64, y: f64) -> f64 {
x * y
}
Documentation and Comments
You can document your functions using comments and documentation comments (///
), which are used to
generate API documentation.
Documentation Comments
rust/// Adds two integers together.
///
/// # Examples
///
/// ```
/// let result = add(2, 3);
/// assert_eq!(result, 5);
/// ```
fn add(a: i32, b: i32) -> i32 {
a + b
}
Summary
- Defining Functions: Use
fn
keyword followed by function name, parameters, and body. - Parameters: Functions can take parameters, and you specify their types.
- Return Values: Functions can return values using
->
and return the value of the last expression by default. - Early Return: Use
return
keyword for early exits. - Functions as First-Class Citizens: Functions can be passed as arguments and returned from other functions.
- Closures: Anonymous functions that capture their environment.
- Type Annotations: Specify parameter and return types explicitly.
- Documentation: Use comments to document functions for better clarity and API documentation.
These features make Rust functions powerful and flexible, allowing for clean and efficient code.