Menu
Coddy logo textTech

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 icon

Challenge

Easy

Let'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 called MyBox<T> with a private field contents of type T. Implement methods for this struct:
    • A new associated function that creates a new MyBox with the given value
    • A peek method that returns a reference to the contents (using &self)
    • A replace method that takes a new value and replaces the current contents (using &mut self)
  • 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:

  1. Creating a box with an integer (first input, parsed as i32)
  2. Peeking at its contents and printing the value
  3. Replacing the contents with a new integer (second input, parsed as i32)
  4. Peeking again to show the updated value
  5. Creating a second box with a string (third input)
  6. 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: Rust

You 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}"
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming