codingstuff.io
ExploreTutorialsProblemsCS Subjects
Get Started
ExploreTutorialsProblemsCS Subjects
Get Started
codingstuff.io

Master the art of building software through interactive tutorials, real-world problems, and guided projects.

Pune, Maharashtra, India

codingstuffmail@gmail.com

Product

  • Explore
  • Tutorials
  • Problems
  • CS Subjects

Company

  • About
  • Contact
  • Privacy Policy
  • Terms & Conditions
  • Sitemap

© 2026 codingstuff.io. All rights reserved.

Built with ❤️ for developers everywhere

/
/
All Tutorials
🦀

Rust

32 / 58 topics
32Generics33Traits34Trait Objects
Tutorials/Rust/Generics
🦀Rust

Generics

Updated 2026-04-20
3 min read

Generics

Generics are a powerful feature in Rust that allow you to write code that is more flexible and reusable. By using generics, you can define functions, structs, enums, and traits that work with multiple types without sacrificing type safety. This makes your code more generic and adaptable to different use cases.

Introduction to Generics

Generics enable you to abstract over types in a way that allows you to write code that works for any type that meets certain criteria. In Rust, generics are used extensively to create collections like Vec<T> and HashMap<K, V>, where T and K, V represent generic types.

Defining Generic Functions

To define a generic function, you use angle brackets (<>) after the function name to declare one or more type parameters. Here's an example of a simple generic function that takes two arguments of the same type and returns their sum:

fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {
    a + b
}

fn main() {
    let integer_sum = add(5, 10);
    let float_sum = add(3.5, 2.8);

    println!("Integer sum: {}", integer_sum); // Output: Integer sum: 15
    println!("Float sum: {}", float_sum);     // Output: Float sum: 6.3
}

In this example, T is a type parameter that represents the generic type of the arguments and return value. The trait bound <T: std::ops::Add<Output = T>> ensures that the type T implements the Add trait with an output type of T.

Defining Generic Structs

You can also define structs with generic types. Here's an example of a generic struct called Point that can represent points in 2D space with any numeric type:

struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn new(x: T, y: T) -> Self {
        Point { x, y }
    }

    fn distance_from_origin(&self) -> f64
    where
        T: std::ops::Add<Output = T> + std::ops::Mul<Output = T> + Into<f64>,
    {
        ((self.x.into() * self.x.into()) + (self.y.into() * self.y.into())).sqrt()
    }
}

fn main() {
    let integer_point = Point::new(3, 4);
    let float_point = Point::new(3.0, 4.0);

    println!("Distance from origin: {}", integer_point.distance_from_origin()); // Output: Distance from origin: 5
    println!("Distance from origin: {}", float_point.distance_from_origin());   // Output: Distance from origin: 5
}

In this example, the Point struct is defined with a generic type parameter T. The distance_from_origin method calculates the Euclidean distance of the point from the origin. The trait bounds in the where clause ensure that the type T can be added, multiplied, and converted to an f64.

Defining Generic Enums

Enums can also be generic. Here's an example of a generic enum called Option<T> which represents optional values:

enum Option<T> {
    Some(T),
    None,
}

fn main() {
    let some_number = Option::Some(5);
    let absent_number: Option<i32> = Option::None;

    match some_number {
        Option::Some(value) => println!("The value is {}", value), // Output: The value is 5
        Option::None => println!("No value"),
    }

    match absent_number {
        Option::Some(value) => println!("The value is {}", value),
        Option::None => println!("No value"), // Output: No value
    }
}

In this example, the Option enum has a generic type parameter T. It can hold either a value of type T wrapped in Some, or no value represented by None.

Generic Traits

Traits can also be generic. Here's an example of a generic trait called Summary that defines a method to summarize any type:

trait Summary {
    fn summarize(&self) -> String;
}

struct NewsArticle {
    headline: String,
    location: String,
    author: String,
    content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

fn main() {
    let article = NewsArticle {
        headline: "Rust generics are powerful".to_string(),
        location: "World".to_string(),
        author: "John Doe".to_string(),
        content: "Generics in Rust allow for flexible and reusable code.".to_string(),
    };

    println!("Summary: {}", article.summarize()); // Output: Summary: Rust generics are powerful, by John Doe (World)
}

In this example, the Summary trait is defined with a generic type parameter. The NewsArticle struct implements the Summary trait, providing its own implementation of the summarize method.

Best Practices

  1. Use Generics Sparingly: While generics are powerful, they can make your code more complex and harder to understand if overused. Use them only when necessary.
  2. Trait Bounds for Type Safety: Always specify trait bounds for generic types to ensure that the operations you perform on these types are valid.
  3. Generics in Traits: When defining traits with generics, consider using associated types or default implementations to make your code more flexible and reusable.
  4. Performance Considerations: Generics can sometimes lead to performance overhead due to monomorphization (the process of generating concrete implementations for each generic type). However, Rust's compiler is quite good at optimizing these cases.

Conclusion

Generics are a fundamental feature in Rust that enable you to write flexible and reusable code. By using generics, you can abstract over types while maintaining type safety. This makes your code more adaptable to different use cases and reduces code duplication. In this tutorial, we explored how to define generic functions, structs, enums, and traits, as well as best practices for using generics effectively in Rust.

By mastering generics, you'll be able to write more powerful and maintainable Rust programs that can handle a wide variety of data types with ease.


PreviousUnsafe RustNext Traits

Recommended Gear

Unsafe RustTraits