Rust-এ Traits & Generics – In-depth
A self-motivated and enthusiastic web developer with a deep interest in JavaScript (React.js). To work in the Software industry with modern web technologies of different local & multinational Software/ IT agencies of Bangladesh and grow rapidly with increasing responsibilities.
Rust একটি memory safe এবং flexible language, যেখানে Traits এবং Generics code reuse এবং flexible behavior design করার জন্য খুব গুরুত্বপূর্ণ।
১️. Generics – Flexible Type
Generics হলো Rust-এর feature যা function, struct বা enum কে কোনো specific type এর উপর নির্ভর না করে তৈরি করতে দেয়।
উদাহরণ:
ধরো আমরা একটি online shop-এর জন্য function চাই যা সব ধরনের product price থেকে সবচেয়ে বড় price বের করবে।
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let int_prices = vec![100, 250, 150];
let float_prices = vec![99.5, 150.75, 120.0];
println!("Most expensive (int): {}", largest(&int_prices));
println!("Most expensive (float): {}", largest(&float_prices));
}
ব্যাখ্যা:
T→ Generic type, function call-এর সময় decide হয়।T: PartialOrd→ type comparison করতে পারবে।একই function দিয়ে different type (i32, f64) handle করা যায়।
Real-life meaning:
এক shop-এ বিভিন্ন ধরনের product price compare করতে পারছ।
Code reuse এবং type safety বজায় থাকে।
Struct + Generics Example:
struct Product<T> {
name: String,
price: T,
}
fn main() {
let laptop = Product { name: "Laptop".to_string(), price: 1200 };
let phone = Product { name: "Phone".to_string(), price: 699.99 };
println!("{} costs {:?}", laptop.name, laptop.price);
println!("{} costs {:?}", phone.name, phone.price);
}
এখানে
Product<T>generic struct → price যে type-ই হোক, support করে।একে type-safe এবং reusable রাখা হয়েছে।
২️. Traits – Shared Behavior
Traits হলো Rust-এর interface এর মতো। এটা বলে কোন type কি ধরনের behavior (methods) support করবে।
উদাহরণ: Pet Shop
ধরো একটি Pet Shop আছে। বিভিন্ন Pet আছে: Dog, Cat, Parrot। সব Pet speak করতে পারবে, কিন্তু শব্দ আলাদা।
trait Speak {
fn speak(&self);
}
struct Dog;
struct Cat;
struct Parrot;
impl Speak for Dog {
fn speak(&self) { println!("Woof!"); }
}
impl Speak for Cat {
fn speak(&self) { println!("Meow!"); }
}
impl Speak for Parrot {
fn speak(&self) { println!("Squawk!"); }
}
// Generic function with Trait Bound
fn make_pet_speak<T: Speak>(pet: T) {
pet.speak();
}
fn main() {
let pets: Vec<Box<dyn Speak>> = vec![
Box::new(Dog),
Box::new(Cat),
Box::new(Parrot),
];
for pet in pets {
pet.speak();
}
}
ব্যাখ্যা:
trait Speak→ shared behavior define করে।impl Speak for Dog/Cat/Parrot→ প্রতিটি Pet নিজস্ব behavior define করে।Box<dyn Speak>→ runtime polymorphism, vector-এ সব Pet একসাথে রাখা যায়।
Real-life meaning:
Pet Shop-এর সব pet কে speak করতে বলা যায়, type যেটাই হোক না কেন।
Behavior flexible, code modular এবং clean।
Rust-এ dyn কি?
dyn হলো Rust-এর dynamic dispatch এর জন্য ব্যবহৃত keyword। এটি বলছে, “এই object যেকোনো type হতে পারে, যেটি এই trait implement করেছে।”
সংক্ষেপে:
Normally Rust compile-time dispatch ব্যবহার করে।
dyn Traituse করলে runtime dispatch হয়।dynallows heterogeneous types in a single variable বা collection।
১️ .Basic Example
ধরো আমাদের কাছে কিছু pet আছে, যেগুলো Speak trait implement করেছে:
trait Speak {
fn speak(&self);
}
struct Dog;
struct Cat;
impl Speak for Dog {
fn speak(&self) { println!("Woof!"); }
}
impl Speak for Cat {
fn speak(&self) { println!("Meow!"); }
}
fn main() {
let dog: Box<dyn Speak> = Box::new(Dog);
let cat: Box<dyn Speak> = Box::new(Cat);
dog.speak(); // Woof!
cat.speak(); // Meow!
}
ব্যাখ্যা:
Box<dyn Speak>→ heap-allocated pointer, runtime-এ actual type decide হয়।Compile-time-এ Rust জানে না ঠিক কোন type হবে → dynamic dispatch।
Method call
speak()→ function pointer table (vtable) ব্যবহার করে ঠিক কোন function call হবে runtime-এ।
2. কেন dyn দরকার?
Rust normally static dispatch use করে:
fn make_speak<T: Speak>(animal: T) {
animal.speak();
}
Tcompile-time-এ resolve হয়।Type fixed, memory stack-based, fast.
কিন্তু heterogeneous collection চাইলে:
let pets: Vec<Box<dyn Speak>> = vec![Box::new(Dog), Box::new(Cat)];
এখানে সব pet একসাথে রাখা দরকার।
Compile-time-এ type একই নয় →
dynব্যবহার করতে হবে।
৩️. Memory & Dispatch Level
Box<dyn Trait>memory:
[Pointer to heap data] + [Pointer to vtable]
Heap-allocated data → actual struct (Dog, Cat)
vtable pointer → function pointer table, যা বলে কোন method call হবে
- Dynamic dispatch:
pet.speak()call → vtable থেকে method pointer lookup → call actual functionExtra runtime cost থাকে (vtable lookup), কিন্তু type flexibility বেশি।
dynvs Generic Trait Bound
| Feature | Syntax | Dispatch | Memory | Use Case |
| Generic | T: Trait | Compile-time | Stack | Type known at compile-time, fastest |
| Dynamic | dyn Trait | Runtime | Heap + vtable | Heterogeneous types, collection of different types |
Generics + Traits একসাথে
Generics দিয়ে আমরা function বা struct flexible করি।
Traits দিয়ে আমরা constraint দেই যে এই type কী behavior support করবে।
উদাহরণ:
trait Discount {
fn discount(&self) -> f64;
}
struct Product {
name: String,
price: f64,
}
impl Discount for Product {
fn discount(&self) -> f64 {
self.price * 0.1 // 10% discount
}
}
fn print_discount<T: Discount>(item: &T) {
println!("Discount: {}", item.discount());
}
fn main() {
let laptop = Product { name: "Laptop".to_string(), price: 1200.0 };
print_discount(&laptop);
}
ব্যাখ্যা:
Discounttrait → defines behaviorProductimplementsDiscount→ actual implementationGeneric function
print_discount<T: Discount>→ accepts any type যা Discount implement করে
Real-life meaning:
Shop-এ multiple product type থাকলেও একই way-তে discount calculate করা যায়।
Type-safe, flexible এবং reusable।




