Objective
Create Functions in Rust
By the end of this lesson, you will understand how to define and call functions in Rust. You’ll learn about parameters, return values, function scope, and advanced function features.
1. Defining Functions
In Rust, functions are defined using the fn
keyword, followed by the function name, parameters, and an optional return type. The basic syntax is as follows:
fn function_name(parameters) -> return_type {
// function body
}
Example: Basic Function
Here’s a simple function that takes no parameters and returns nothing:
fn say_hello() {
println!("Hello, Rust!");
}
fn main() {
say_hello(); // Calling the function
}
2. Functions with Parameters
Functions can accept parameters to work with data. You specify the type of each parameter in the function definition.
Example: Function with Parameters
fn greet(name: &str) {
println!("Hello, {}!", name);
}
fn main() {
greet("Alice"); // Calling the function with an argument
}
3. Return Values
Functions can return values using the ->
syntax. The return type must be specified after the parameters. The last expression in the function body is the return value.
Example: Function with a Return Value
fn add(a: i32, b: i32) -> i32 {
a + b // The last expression is returned
}
fn main() {
let sum = add(5, 10);
println!("Sum: {}", sum);
}
4. Function Scope
Variables defined inside a function are not accessible outside of it, known as function scope. You can return values from functions to use them elsewhere.
Example: Scope of Variables
fn main() {
let x = 5;
fn inner_function() {
let y = 10; // y is scoped to inner_function
println!("Inner y: {}", y);
}
inner_function();
println!("Outer x: {}", x); // This works
// println!("Inner y: {}", y); // This would NOT work, y is out of scope
}
5. Complex Functions: Multiple Parameters and Return Types
You can define functions that take multiple parameters and return multiple values using tuples.
Example: Function with Multiple Parameters
fn calculate_area_and_perimeter(length: f64, width: f64) -> (f64, f64) {
let area = length * width;
let perimeter = 2.0 * (length + width);
(area, perimeter) // Return a tuple containing both values
}
fn main() {
let (area, perimeter) = calculate_area_and_perimeter(5.0, 3.0);
println!("Area: {}, Perimeter: {}", area, perimeter);
}
6. Advanced Functions: Closures
In Rust, closures are functions that can capture the environment in which they are defined. This allows them to access variables from the surrounding scope.
Example: Closure
fn main() {
let multiplier = 2;
let multiply = |x: i32| x * multiplier; // Closure captures the variable multiplier
let result = multiply(5); // Call the closure
println!("Result: {}", result); // Output: Result: 10
}
7. Functions as First-Class Citizens
In Rust, functions are first-class citizens, meaning you can pass functions as arguments, return them from other functions, and assign them to variables.
Example: Passing Functions as Arguments
You can define a function that takes another function as a parameter:
fn apply_function<F>(f: F, value: i32)
where
F: Fn(i32) -> i32,
{
let result = f(value);
println!("Result: {}", result);
}
fn double(x: i32) -> i32 {
x * 2
}
fn main() {
apply_function(double, 5); // Passing the double function as an argument
}
8. Conclusion
In this lesson, you learned how to define and call functions in Rust, explore parameters and return values, and understand function scope. You also delved into complex functions with multiple parameters and return types, as well as closures and the concept of functions as first-class citizens. These foundational concepts are vital for building robust Rust applications.