Generic functions in Rust - Time & Space Complexity
We want to see how the time a generic function takes changes as the input size grows.
How does using a generic type affect the speed when the function runs?
Analyze the time complexity of the following code snippet.
fn print_items(items: &[T]) {
for item in items {
println!("{}", item);
}
}
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
print_items(&numbers);
}
This function prints each item in a list, using a generic type that can be any printable value.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Looping through each item in the list.
- How many times: Once for every item in the input slice.
As the list gets bigger, the function prints more items, so it takes longer.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 print actions |
| 100 | 100 print actions |
| 1000 | 1000 print actions |
Pattern observation: The time grows directly with the number of items; doubling items doubles the work.
Time Complexity: O(n)
This means the time to run grows in a straight line with the number of items to print.
[X] Wrong: "Using generics makes the function slower because it has to handle many types."
[OK] Correct: The generic function runs the same loop regardless of type; the time depends on input size, not the type itself.
Understanding how generic functions behave helps you explain code efficiency clearly and confidently in real projects and interviews.
"What if we changed the function to print pairs of items instead of single items? How would the time complexity change?"
Practice
<T> mean in a Rust function definition like fn example<T>(value: T) {}?Solution
Step 1: Understand the syntax
The<T>in Rust<T>after the function name declares a generic type parameter namedT.Step 2: Explain the effect of generic type parameter
This allows the function to accept any type forvalue, making it flexible and reusable.Final Answer:
It makes the function generic, so it can accept any type. -> Option AQuick Check:
Generic type parameter = flexible function input [OK]
<T> after function name for generics [OK]- Thinking
<T>is a variable declaration - Assuming it restricts to one type like integer
- Confusing it with unsafe code marker
print_value that takes one argument of any type 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 usesvalue: Tas parameter type.Final Answer:
fn print_value<T>(value: T) {} -> Option BQuick Check:
Generic syntax =fn name<T>(param: T)[OK]
- Putting
Tinside parameter parentheses incorrectly - Using angle brackets around parameter type
- Missing angle brackets after function name
fn show_value<T: std::fmt::Display>(val: T) {
println!("Value: {}", val);
}
fn main() {
show_value(10);
show_value("hello");
}Solution
Step 1: Understand the generic function with trait bound
The functionshow_valuerequiresTto implementDisplayso it can be printed.Step 2: Check calls with integer and string
Both10(integer) and"hello"(string) implementDisplay, so both calls print correctly.Final Answer:
Value: 10 Value: hello -> Option AQuick Check:
Trait bound allows printing = output shown [OK]
- Assuming generic functions print without trait bounds
- Thinking string prints as number
- Expecting compilation error without trait bound
fn compare<T>(a: T, b: T) -> bool {
a == b
}Solution
Step 1: Understand use of
The==in generic function==operator requires the typeTto implement thePartialEqtrait.Step 2: Identify missing trait bound
The function lacksT: PartialEqbound, so compiler will error when using==.Final Answer:
Missing trait boundT: PartialEqto use==operator. -> Option DQuick Check:
Operator needs trait bound = addT: PartialEq[OK]
- Ignoring trait bounds for operators
- Changing return type unnecessarily
- Replacing generic with concrete type without reason
largest that returns the largest element from a slice of any type T. Which of these is the correct way to define it?Solution
Step 1: Identify required traits for comparison and copying
To compare elements with>,Tmust implementPartialOrd. To copy elements,Copytrait 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 addsT: PartialOrd + Copyand uses a loop to find the largest element.Final Answer:
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T { ... } -> Option CQuick Check:
Traits PartialOrd + Copy needed for generic largest function [OK]
- Omitting trait bounds causing compile errors
- Returning wrong type or missing copy trait
- Using concrete types instead of generics
Ready to prove it?
Pass the test and this pattern moves unknown
