📖 Scenario: You are building a small Rust program that can work with different types of data using a single function. This helps avoid repeating code for each data type.
🎯 Goal: Create a generic function in Rust that can take two values of the same type and return the larger one. You will practice writing generic functions and calling them with different types.
📋 What You'll Learn
Create a generic function named largest that takes two parameters of the same generic type T.
Add a trait bound to T so it can be compared using the greater than operator.
Call the largest function with two i32 values and print the result.
Call the largest function with two f64 values and print the result.
💡 Why This Matters
🌍 Real World
Generic functions let programmers write flexible code that works with many data types without repeating themselves.
💼 Career
Understanding generics is important for writing clean, reusable code in Rust and many other programming languages.
Progress0 / 4 steps
1
Create a generic function skeleton
Write a generic function named largest that takes two parameters a and b of the same generic type T. For now, just return a without any comparison.
Rust
Hint
Use fn largest(a: T, b: T) -> T to define a generic function.
2
Add trait bound for comparison
Modify the largest function to add a trait bound so that T can be compared using the greater than operator. Use PartialOrd and Copy traits. Then return the larger of a and b using an if expression.
Rust
Hint
Use T: PartialOrd + Copy to allow comparison and copying.
3
Call the generic function with integers
Call the largest function with two i32 values: 10 and 20. Store the result in a variable named result_int.
Rust
Hint
Call largest(10, 20) and assign to result_int.
4
Call the generic function with floats and print results
Call the largest function with two f64 values: 3.5 and 2.7. Store the result in a variable named result_float. Then print both result_int and result_float using println!.
Rust
Hint
Use println!("Largest integer: {}", result_int); and similarly for result_float.
Practice
(1/5)
1. What does the <T> mean in a Rust function definition like fn example<T>(value: T) {}?
easy
A. It makes the function generic, so it can accept any type.
B. It defines a new variable inside the function.
C. It restricts the function to only work with integers.
D. It marks the function as unsafe.
Solution
Step 1: Understand the syntax <T> in Rust
The <T> after the function name declares a generic type parameter named T.
Step 2: Explain the effect of generic type parameter
This allows the function to accept any type for value, making it flexible and reusable.
Final Answer:
It makes the function generic, so it can accept any type. -> Option A
Quick Check:
Generic type parameter = flexible function input [OK]
Hint: Look for <T> after function name for generics [OK]
Common Mistakes:
Thinking <T> is a variable declaration
Assuming it restricts to one type like integer
Confusing it with unsafe code marker
2. Which of the following is the correct syntax to define a generic function named print_value that takes one argument of any type T?
easy
A. fn print_value(T value) {}
B. fn print_value<T>(value: T) {}
C. fn print_value(value: <T>) {}
D. fn print_value(value: T<>) {}
Solution
Step 1: Recall generic function syntax in Rust
Generic functions use <T> after the function name to declare the generic type.
Step 2: Match the syntax with options
fn print_value<T>(value: T) {} correctly places <T> after the function name and uses value: T as parameter type.
Final Answer:
fn print_value<T>(value: T) {} -> Option B
Quick Check:
Generic syntax = fn name<T>(param: T) [OK]
Hint: Generic type always goes after function name in angle brackets [OK]
Common Mistakes:
Putting T inside parameter parentheses incorrectly
Hint: Add trait bounds when using operators on generics [OK]
Common Mistakes:
Ignoring trait bounds for operators
Changing return type unnecessarily
Replacing generic with concrete type without reason
5. You want to write a generic function largest that returns the largest element from a slice of any type T. Which of these is the correct way to define it?
hard
A. fn largest<T>(list: &[T]) -> T { let mut largest = list[0]; for &item in list { if item > largest { largest = item; } } largest }
B. fn largest(list: &[i32]) -> i32 { let mut largest = list[0]; for &item in list { if item > largest { largest = item; } } largest }
C. fn largest<T: PartialOrd + Copy>(list: &[T]) -> T { let mut largest = *list[0]; for &item in list { if item > largest { largest = item; } } largest }
D. fn largest<T: PartialEq>(list: &[T]) -> T { list[0] }
Solution
Step 1: Identify required traits for comparison and copying
To compare elements with >, T must implement PartialOrd. To copy elements, Copy trait is needed.
Step 2: Check function signature and body
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T { let mut largest = *list[0]; for &item in list { if item > largest { largest = item; } } largest } correctly adds T: PartialOrd + Copy and uses a loop to find the largest element.
Final Answer:
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T { ... } -> Option C
Quick Check:
Traits PartialOrd + Copy needed for generic largest function [OK]
Hint: Add PartialOrd and Copy traits for generic comparisons [OK]
Common Mistakes:
Omitting trait bounds causing compile errors
Returning wrong type or missing copy trait
Using concrete types instead of generics
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.