Generic Methods
Part of the Object Oriented Programming section of Coddy's Rust journey — lesson 25 of 61.
A generic struct can hold any type, but it's not very useful without methods to interact with its data. To define methods for a generic struct, you need a special syntax in the impl block.
The key is declaring the generic parameter on the impl itself:
struct Wrapper<T> {
value: T,
}
impl<T> Wrapper<T> {
fn get(&self) -> &T {
&self.value
}
}
Notice the impl<T> before Wrapper<T>. This tells Rust that T is a generic type parameter for the entire implementation block. Without this declaration, Rust would look for a concrete type named T and fail to find it.
The get method returns &T—a reference to whatever type the wrapper holds. This works whether T is an integer, a string, or any other type:
let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };
println!("{}", num_wrapper.get()); // 100
println!("{}", text_wrapper.get()); // Rust
The same method definition works for both, because the generic T adapts to each concrete type at compile time.
Challenge
EasyLet's extend your generic container with methods! You'll build a Box struct (not to be confused with Rust's standard Box) that can hold any type and provides methods to interact with its contents.
You'll organize your code across two files:
mybox.rs: Define a public generic struct calledMyBox<T>with a private fieldcontentsof typeT. Implement methods for this struct:- A
newassociated function that creates a newMyBoxwith the given value - A
peekmethod that returns a reference to the contents (using&self) - A
replacemethod that takes a new value and replaces the current contents (using&mut self)
- A
main.rs: Bring in your module and demonstrate the generic methods working with different types. You'll create boxes, peek at their contents, and replace values to show the methods in action.
Remember the key syntax for implementing methods on a generic struct: you need impl<T> before MyBox<T> to tell Rust that T is a generic parameter for the entire implementation block.
In your main file, demonstrate your MyBox by:
- Creating a box with an integer (first input, parsed as
i32) - Peeking at its contents and printing the value
- Replacing the contents with a new integer (second input, parsed as
i32) - Peeking again to show the updated value
- Creating a second box with a string (third input)
- Peeking at the string box's contents
Your output should follow this format:
Integer box contains: {value}
After replace: {value}
String box contains: {value}For example, with inputs 10, 25, and Rust:
Integer box contains: 10
After replace: 25
String box contains: RustYou will receive three inputs: an initial integer, a replacement integer, and a string value.
Cheat sheet
To define methods for a generic struct, declare the generic parameter on the impl block:
struct Wrapper<T> {
value: T,
}
impl<T> Wrapper<T> {
fn get(&self) -> &T {
&self.value
}
}
The impl<T> syntax tells Rust that T is a generic type parameter for the entire implementation block. Without this, Rust would look for a concrete type named T.
Methods can return references to the generic type (&T), which works for any concrete type:
let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };
println!("{}", num_wrapper.get()); // 100
println!("{}", text_wrapper.get()); // Rust
Try it yourself
mod mybox;
use mybox::MyBox;
fn main() {
// Read inputs
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let initial_int: i32 = input1.trim().parse().expect("Invalid integer");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let replacement_int: i32 = input2.trim().parse().expect("Invalid integer");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let string_value = input3.trim().to_string();
// TODO: Create a MyBox with the initial integer
// TODO: Peek at its contents and print: "Integer box contains: {value}"
// TODO: Replace the contents with the replacement integer
// TODO: Peek again and print: "After replace: {value}"
// TODO: Create a second MyBox with the string value
// TODO: Peek at the string box and print: "String box contains: {value}"
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Methods and Behavior
Intro Implementation BlocksThe Self ParameterMutable MethodsAssociated FunctionsMultiple Implementation BlocksMethod ChainingRecap - Rectangle Actions4Project: Virtual Pet
Defining the PetFeeding the Pet7Standard Traits
The Debug TraitThe Display TraitClone and CopyEquality TraitsRecap - Printable Point10Project: Document System
The Draw TraitText Component2Encapsulation and Modules
Modules BasicsThe Public KeywordPrivate FieldsGettersSettersRecap - Secure Locker5Generics
Generic StructsGeneric MethodsMultiple Generic TypesGeneric FunctionsRecap - Coordinate Point8Traits as Bounds
Trait Bounds SyntaxMultiple BoundsThe Where ClauseReturning Types with TraitsRecap - Generic Printer11Design Patterns in Rust
Newtype PatternCompositionThe Drop TraitFrom and IntoRecap - Smart Pointer Mock