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
ruststruct 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:
Personis a struct with fieldsnameandage.- The
implblock 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
rusttrait 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:
Greetis a trait that defines agreetmethod.Personimplements theGreettrait, providing its own implementation of thegreetmethod.
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
ruststruct 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:
Personhas anAddressstruct as a field, demonstrating composition.
4. Encapsulation
Encapsulation is achieved in Rust by controlling the visibility of fields and methods.
Private and Public Fields
rustpub 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:
nameis a public field, whileageis private.- Access to
ageis controlled through theget_agemethod.
5. Polymorphism
Rust achieves polymorphism through traits. Different types can implement the same trait, allowing for polymorphic behavior.
Trait Polymorphism
rusttrait 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:
DogandCatboth implement theAnimaltrait.make_animal_soundfunction can accept any type that implementsAnimal, 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.