techmore.in

Rust - OOPs

Rust does not follow traditional Object-Oriented Programming (OOP) paradigms exactly as seen in languages like Java or C++. Instead, Rust uses its own approach to achieve similar goals through concepts such as ownership, traits, and composition. Here’s an overview of how Rust supports OOP principles:

1. Structs

Structs in Rust are similar to classes in OOP languages. They are used to create custom data types.

Defining a Struct

rust
struct Person { name: String, age: u32, } impl Person { // Associated function fn new(name: &str, age: u32) -> Person { Person { name: name.to_string(), age, } } // Method fn greet(&self) { println!("Hello, my name is {} and I am {} years old.", self.name, self.age); } } fn main() { let person = Person::new("Alice", 30); person.greet(); }

In this example:

  • Person is a struct with fields name and age.
  • The impl block is used to define methods and associated functions for the struct.

2. Traits

Traits in Rust are similar to interfaces or abstract classes in OOP. They define functionality that can be shared across different types.

Defining a Trait

rust
trait Greet { fn greet(&self); } struct Person { name: String, age: u32, } impl Greet for Person { fn greet(&self) { println!("Hello, my name is {} and I am {} years old.", self.name, self.age); } } fn main() { let person = Person { name: "Alice".to_string(), age: 30, }; person.greet(); }

Here:

  • Greet is a trait that defines a greet method.
  • Person implements the Greet trait, providing its own implementation of the greet method.

3. Inheritance and Composition

Rust does not support traditional inheritance but uses composition and traits to achieve similar outcomes. Composition involves including other types inside a struct.

Using Composition

rust
struct Address { city: String, state: String, } struct Person { name: String, age: u32, address: Address, } impl Person { fn display_address(&self) { println!("Address: {}, {}", self.address.city, self.address.state); } } fn main() { let address = Address { city: "Wonderland".to_string(), state: "CA".to_string(), }; let person = Person { name: "Alice".to_string(), age: 30, address, }; person.display_address(); }

In this example:

  • Person has an Address struct as a field, demonstrating composition.

4. Encapsulation

Encapsulation is achieved in Rust by controlling the visibility of fields and methods.

Private and Public Fields

rust
pub struct Person { pub name: String, age: u32, // Private field } impl Person { pub fn new(name: &str, age: u32) -> Person { Person { name: name.to_string(), age, } } pub fn get_age(&self) -> u32 { self.age } } fn main() { let person = Person::new("Alice", 30); println!("Name: {}", person.name); // Accessible println!("Age: {}", person.get_age()); // Accessed via method }

Here:

  • name is a public field, while age is private.
  • Access to age is controlled through the get_age method.

5. Polymorphism

Rust achieves polymorphism through traits. Different types can implement the same trait, allowing for polymorphic behavior.

Trait Polymorphism

rust
trait Animal { fn make_sound(&self); } struct Dog; struct Cat; impl Animal for Dog { fn make_sound(&self) { println!("Woof!"); } } impl Animal for Cat { fn make_sound(&self) { println!("Meow!"); } } fn make_animal_sound(animal: &dyn Animal) { animal.make_sound(); } fn main() { let dog = Dog; let cat = Cat; make_animal_sound(&dog); make_animal_sound(&cat); }

In this example:

  • Dog and Cat both implement the Animal trait.
  • make_animal_sound function can accept any type that implements Animal, demonstrating polymorphism.

Summary

  • Structs: Define custom data types with fields and methods.
  • Traits: Define shared functionality across types, similar to interfaces.
  • Composition: Use structs within structs for code reuse and organization.
  • Encapsulation: Control visibility of fields and methods using pub.
  • Polymorphism: Achieve through traits and trait objects.

Rust’s approach to OOP is centered around its unique features, like ownership and borrowing, which ensures safety and concurrency without traditional inheritance.