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

CHIRAG KUMARCHIRAG KUMAR
2 min read

✨ 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);

πŸ‘΄ 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
}

πŸ“¦ 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());

🧱 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 };

πŸ’‘ 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 }
}

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();

βœ… 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/

0
Subscribe to my newsletter

Read articles from CHIRAG KUMAR directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

CHIRAG KUMAR
CHIRAG KUMAR

Full stack Developer