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:
Person
is a struct with fieldsname
andage
.- 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
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:
Greet
is a trait that defines agreet
method.Person
implements theGreet
trait, providing its own implementation of thegreet
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
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:
Person
has anAddress
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
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:
name
is a public field, whileage
is private.- Access to
age
is controlled through theget_age
method.
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:
Dog
andCat
both implement theAnimal
trait.make_animal_sound
function 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.