Function Declaration and Error Handling
1. Welcome and Icebreaker:
Welcome back!
If you could create a custom error message for a real-life situation, what situation would it be, and what would the error message say?
2. Outline the Session:
Here’s our plan:
- Concept Explanation: We’ll cover function syntax, parameters, return types, and the different ways functions can be defined. Then, we’ll discuss unrecoverable errors and how to use
panic!to signal them. - Live Coding Demonstration: We’ll write code examples to demonstrate various function definitions and how to use
panic!appropriately. - Tasks: You’ll get exercises to practice defining functions and handling error conditions.
Learning Outcomes: By the end of this session, you will be able to:
- Declare and define functions with different parameter types and return types.
- Call functions and pass arguments.
- Understand the concept of function scope.
- Use the
panic!macro to signal unrecoverable errors. - Understand the difference between recoverable and unrecoverable errors (we’ll cover recoverable errors in more detail later).
Expectations: Experiment with the code! Try different function signatures and see how panic! affects program execution.
3. Concept Explanation:
Function Declarations:
- Functions are declared using the
fnkeyword. - Function names follow the
snake_caseconvention (lowercase words separated by underscores). - Parameters are specified within parentheses
(), with their types. - The return type is specified after an arrow
>. If a function doesn’t return a value, the return type is omitted (it’s implicitly(), the unit type). - The function body is enclosed in curly braces
{}.
fn add(x: i32, y: i32) -> i32 { // Function signature
x + y // Return value (implicit return - no semicolon)
}
fn greet(name: &str) { // No return value
println!("Hello, {}!", name);
}
fn do_nothing() {} //Equivalent to fn do_nothing() -> () {}
Function Scope:
- Variables declared inside a function are only accessible within that function’s scope.
- Functions can access variables from outer scopes (e.g., global variables), but it’s generally better to pass data as arguments.
Unrecoverable Errors and panic!:
panic!is a macro used to signal unrecoverable errors – situations where the program cannot continue execution safely.- When
panic!is called, the program will:- Print an error message.
- Unwind the stack (clean up resources).
- Terminate.
- When to use
panic!:- Logic Errors: When your code encounters a situation that should never happen according to your program’s logic (e.g., an invalid index into an array, a null pointer dereference).
- Unrecoverable External Errors: When an external resource (like a file or network connection) is unavailable in a way that you cannot recover from.
- During Development/Testing: To quickly identify and halt execution when unexpected conditions occur.
- Prototypes/Examples: It’s sometimes acceptable to use
panic!in quick prototypes or examples where robust error handling is not the primary focus.
- When not to use
panic!:- Expected Errors: For errors that you can reasonably anticipate and handle (e.g., user input validation, file not found). Use
Resultfor these (covered in a later session).
- Expected Errors: For errors that you can reasonably anticipate and handle (e.g., user input validation, file not found). Use
4. Live Coding Demonstration:
fn add(x: i32, y: i32) -> i32 {
x + y // Implicit return
}
fn subtract(x: i32, y: i32) -> i32 {
return x - y; // Explicit return
}
fn greet(name: &str) {
println!("Hello, {}!", name);
}
fn divide(x: f64, y: f64) -> f64 {
if y == 0.0 {
panic!("Division by zero!"); // Unrecoverable error
}
x / y
}
// Function with multiple return
fn get_name_and_age() -> (&'static str, u32) {
("Alice", 30)
}
// Function with no parameters and no return
fn print_message() {
println!("This function has no parameters and returns nothing.");
}
fn main() {
let sum = add(5, 3);
println!("Sum: {}", sum);
let difference = subtract(10, 4);
println!("Difference: {}", difference);
greet("Bob");
let result = divide(10.0, 2.0);
println!("Result: {}", result);
// Uncommenting this line will cause a panic:
// let result2 = divide(5.0, 0.0);
let (name, age) = get_name_and_age();
println!("Name: {}, Age: {}", name, age);
print_message();
// Example of accessing an array out of bounds (will panic)
let numbers = [1, 2, 3];
// let invalid = numbers[5]; // This would panic!
}
Key Takeaways:
- Function Definitions: We demonstrate various function signatures with and without return types.
- Implicit vs. Explicit Return: The last expression in a function without a semicolon is implicitly returned. You can also use the
returnkeyword. panic!: We usepanic!to handle the unrecoverable error of division by zero.- Out-of-Bounds Access: Accessing an array element with an invalid index is a common cause of panics.
- Multiple Return: Return multiple value by wrapping with Tuples
- No Parameter and Return: We can create function without no parameter and return.
5. Tasks
-
Calculator Functions: Write functions for multiplication (
multiply), integer division (divide_int), and modulo (modulo) operations. Each function should take two integer arguments and return an integer. Thedivide_intfunction shouldpanic!if the second argument is zero. -
String Length Function: Write a function called
string_lengththat takes a string slice (&str) as an argument and returns its length as ausize. -
Greeting Function with Optional Age: Write a function called
greet_personthat takes a name (&str) and an optional age (Option<u32>) as arguments. If the age is provided (i.e.,Some(age)), the function should print “Hello, {name}! You are {age} years old.”. If the age is not provided (i.e.,None), it should print “Hello, {name}!”. (We haven’t coveredOptionin detail yet, so here’s how to use it for this task):fn greet_person(name: &str, age: Option<u32>) { match age { Some(age) => println!("Hello, {}! You are {} years old.", name, age), None => println!("Hello, {}!", name), } } // Example usage greet_person("Alice", Some(30)); greet_person("Bob", None); -
Array Access with Panic: Write a function called
get_elementthat takes an array of integers ([i32; N], whereNis a constant size) and an index (usize) as arguments. The function should return the element at the given index. If the index is out of bounds, the function shouldpanic!with a descriptive error message. -
Intentional Panic: Write a small program that intentionally calls
panic!with a custom error message. Run the program and observe the output. -
Multiple return: Write a function that given two number and do addition and multiplication. this function return two type.