Composition over Inheritance in Rust 🎯

beginner
17 min

Composition over Inheritance in Rust 🎯

Welcome to our deep dive into Composition over Inheritance in Rust! In this tutorial, we'll explore why and when to use composition instead of inheritance, and how to do it effectively in Rust. Let's get started!

Table of Contents 📝

  1. What is Composition?
  2. What is Inheritance?
  3. Why Composition over Inheritance in Rust?
  4. Implementing Composition in Rust
    • 4.1 Structs and Traits
    • 4.2 Example: Composition of Shape
  5. Quiz: Composition vs Inheritance
  6. Advanced Composition Examples in Rust

What is Composition? 📝

Composition is a design pattern that combines objects to create more complex objects. Instead of inheriting from a parent class, we create objects and combine them to achieve the desired functionality.

What is Inheritance? 📝

Inheritance is a design pattern where a subclass inherits the properties and methods of its parent class.

Why Composition over Inheritance in Rust? 💡

In Rust, inheritance is limited and can lead to unintended behavior due to its strong type system. Composition, on the other hand, allows for more flexibility, better control over data, and easier code maintenance.

Implementing Composition in Rust 📝

Structs and Traits 📝

In Rust, composition is often achieved through structs and traits. Structs can contain other structs or traits, and traits can be implemented by multiple structs.

Example: Composition of Shape 💡

rust
// Define a trait for Shape trait Shape { fn area(&self) -> f64; } // Define a struct for Circle struct Circle { radius: f64, } impl Shape for Circle { fn area(&self) -> f64 { // Calculate the area of a circle std::f64::consts::PI * self.radius * self.radius } } // Define a struct for Rectangle struct Rectangle { width: f64, height: f64, } impl Shape for Rectangle { fn area(&self) -> f64 { // Calculate the area of a rectangle self.width * self.height } } // Use the composition of Shape fn total_area(shapes: Vec<Box<dyn Shape>>) -> f64 { shapes.iter().fold(0.0, |acc, shape| acc + shape.area()) } fn main() { let circle = Box::new(Circle { radius: 5.0 }); let rectangle = Box::new(Rectangle { width: 4.0, height: 5.0 }); let shapes = vec![circle, rectangle]; println!("Total Area: {}", total_area(shapes)); }

In this example, we define a Shape trait with an area method, and two structs Circle and Rectangle that implement the Shape trait. We then create a function total_area that takes a vector of Shape implementations and calculates the total area.

Quiz: Composition vs Inheritance 🎯

Quick Quiz
Question 1 of 1

Which design pattern allows for more flexibility, better control over data, and easier code maintenance in Rust?

Advanced Composition Examples in Rust 💡

In real-world projects, composition can be used to create complex objects from smaller components, making the code more modular, reusable, and maintainable.

That's all for today! We hope this tutorial has helped you understand Composition over Inheritance in Rust. Happy coding! 🎉