DEV Community

Cover image for πŸ¦€ Rust Series 3: **Generics, Traits & Implementations**
Thor
Thor

Posted on

πŸ¦€ Rust Series 3: **Generics, Traits & Implementations**

✨ Introduction

Welcome back to our Rust learning journey!

In our last post, we explored control flow, functions, and ownership. Today, we dive into three powerful concepts that make Rust both flexible and type-safe:

πŸš€ Generics, Traits, and Implementations


πŸ”§ Generics in Rust

Generics let you write code that works with many different types while keeping Rust’s zero-cost abstraction promise.

// Generic function that works with any type implementing Add
fn sum_of_two_number<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {
    a + b
}

// Usage
let int_result = sum_of_two_number(20, 20);
let float_result = sum_of_two_number(20.20, 20.20);
Enter fullscreen mode Exit fullscreen mode

πŸ‘΄ Without generics, you’d have to write separate functions:

fn sum_u32(a: u32, b: u32) -> u32 {
    a + b
}

fn sum_f32(a: f32, b: f32) -> f32 {
    a + b
}
Enter fullscreen mode Exit fullscreen mode

πŸ“¦ Structs & impl Blocks

You add functionality to types in Rust using impl.

struct Rect {
    width: u32,
    height: u32,
}

impl Rect {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}

// Usage
let rect = Rect { width: 20, height: 30 };
println!("Area: {}", rect.area());
Enter fullscreen mode Exit fullscreen mode

🧱 Generic Structs + Trait Bounds

Structs can be generic too, and we can add functionality using trait bounds.

struct RectWithGeneric<T> {
    width: T,
    height: T,
}

impl<T: std::ops::Add<Output = T> + Copy> RectWithGeneric<T> {
    fn area(&self) -> T {
        self.width + self.height
    }
}

// Usage
let float_rect = RectWithGeneric { width: 20.1, height: 20.2 };
let int_rect = RectWithGeneric { width: 200, height: 200 };
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Traits: Defining Shared Behavior

Traits are like interfaces in other languages β€” they define capabilities that types can implement.

// Display trait for printing
fn print<T: std::fmt::Display>(item: T) {
    println!("{}", item);
}

// Ord trait for comparison
fn max<T: Ord>(a: T, b: T) -> T {
    if a > b { a } else { b }
}
Enter fullscreen mode Exit fullscreen mode

Traits are used everywhere in Rust, including the standard library.


🌱 Real-World: Environment Variables

Here's a real-world use case: reading env vars safely.

use std::env;

// Safe error handling
match env::var("REDIS_INTERNAL") {
    Ok(val) => println!("{}", val),
    Err(_) => println!("Environment variable not found"),
}

// When you're sure it's set (be cautious)
let redis_value = env::var("REDIS_INTERNAL").unwrap();
Enter fullscreen mode Exit fullscreen mode

βœ… what you learnt

  • βœ… Generics allow for type-safe and reusable code
  • βœ… Traits define capabilities for types
  • βœ… impl blocks add methods to structs
  • βœ… Generic structs = power + flexibility
  • βœ… Trait bounds like T: Add + Copy enforce required behavior

πŸ”— Resources

πŸ“˜ Code examples:

github.com/ichiragkumar/rust-basics

🐦 Follow me for more:

https://x.com/imchiragkumar/

Top comments (0)