Functions
## Learning Objectives
- Define and call functions
- Use parameters and return values
- Master method syntax
- Understand pattern matching with match
## Function Basics
### Declaration
```rust
fn function_name() {
// function body
}
```
### Calling Functions
```rust
fn main() {
greet();
greet();
}
fn greet() {
println!("Hello!");
}
```
## Parameters
### Single Parameter
```rust
fn print_number(n: i32) {
println!("Number: {}", n);
}
fn main() {
print_number(42);
}
```
### Multiple Parameters
```rust
fn add(a: i32, b: i32) {
println!("{} + {} = {}", a, b, a + b);
}
fn main() {
add(5, 3);
}
```
### Parameter Naming
```rust
fn greet(name: &str, age: u32) {
println!("Hello {}, you are {} years old", name, age);
}
fn main() {
greet("Alice", 30);
}
```
## Return Values
### Implicit Return
```rust
fn add(a: i32, b: i32) -> i32 {
a + b // No semicolon = return value
}
fn main() {
let sum = add(5, 3);
println!("{}", sum); // Prints: 8
}
```
### Explicit Return
```rust
fn add(a: i32, b: i32) -> i32 {
return a + b; // Explicit return (less common)
}
```
### Early Return
```rust
fn absolute_value(n: i32) -> i32 {
if n < 0 {
return -n; // Early return
}
n // Normal return
}
```
### No Return Value
```rust
fn greet(name: &str) {
println!("Hello, {}!", name);
// No -> return type means () (unit type)
}
fn main() {
let result = greet("Alice"); // result is ()
}
```
## Method Syntax
Methods are functions associated with a type:
```rust
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// &self is reference to the instance
fn area(&self) -> u32 {
self.width * self.height
}
// Method with parameters
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
// Static method (associated function)
fn new(width: u32, height: u32) -> Rectangle {
Rectangle { width, height }
}
}
fn main() {
let rect = Rectangle::new(30, 50);
println!("Area: {}", rect.area());
}
```
## Associated Functions
Associated functions don't take `self` as a parameter:
```rust
impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle { width: size, height: size }
}
}
fn main() {
let sq = Rectangle::square(10);
}
```
## Multiple impl Blocks
```rust
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
impl Rectangle {
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
```
## Pattern Matching with match
```rust
fn main() {
let x = 3;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("something else"),
}
}
```
### match with Values
```rust
fn main() {
let score = 85;
let grade = match score {
90..=100 => "A",
80..=89 => "B",
70..=79 => "C",
60..=69 => "D",
_ => "F",
};
println!("Grade: {}", grade); // Grade: B
}
```
### match with Multiple Statements
```rust
fn main() {
let x = 1;
match x {
1 => {
let y = 2;
println!("x = 1, y = {}", y);
}
2 => println!("x = 2"),
_ => println!("x is something else"),
}
}
```
### match with Bound Variables
```rust
fn main() {
let msg = Some(42);
match msg {
Some(n) => println!("Number: {}", n),
None => println!("No number"),
}
}
```
### if let Syntax
```rust
fn main() {
let msg = Some(42);
// Shorthand for single pattern
if let Some(n) = msg {
println!("Number: {}", n);
}
}
```
### match with Enum
```rust
enum Direction {
North,
South,
East,
West,
}
fn main() {
let direction = Direction::North;
match direction {
Direction::North => println!("Heading north"),
Direction::South => println!("Heading south"),
Direction::East => println!("Heading east"),
Direction::West => println!("Heading west"),
}
}
```
## Closures
Closures are anonymous functions that capture their environment:
```rust
fn main() {
let add_one = |x| x + 1;
println!("{}", add_one(5)); // 6
let add = |a, b| a + b;
println!("{}", add(2, 3)); // 5
// Type annotations
let square = |x: i32| -> i32 { x * x };
println!("{}", square(4)); // 16
}
```
### Closures Capturing Environment
```rust
fn main() {
let x = 10;
// Closure captures x from environment
let closure = || x + 5;
println!("{}", closure()); // 15
}
```
## Higher-Order Functions
```rust
fn apply(x: i32, f: F) -> i32
where
F: Fn(i32) -> i32,
{
f(x)
}
fn main() {
let result = apply(5, |x| x * 2);
println!("{}", result); // 10
}
fn twice(f: F) -> impl Fn(i32) -> i32
where
F: Fn(i32) -> i32,
{
move |x| f(f(x))
}
```
## Summary
- Functions declared with `fn` keyword
- Parameters need type annotations
- Return type specified with `->`
- Last expression returned implicitly (no semicolon)
- Methods defined in `impl` blocks with `&self`
- `match` is exhaustive pattern matching
- `if let` for single pattern matching
- Closures are anonymous functions that capture environment
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →