Rust فاقد پشتیبانی بومی برای OOP است، اما به هر حال میتوانید از این تکنیکها برای استفاده از این الگو استفاده کنید.
برنامه نویسی شی گرا (OOP) طراحی نرم افزار را با تأکید بر استفاده از اشیا برای نمایش موجودیت ها و مفاهیم دنیای واقعی ساده می کند. OOP با کپسوله کردن عملکرد درون اشیا، قابلیت نگهداری را تشویق می کند.
Rust یک زبان انعطاف پذیر است که از برنامه نویسی عملکردی و رویه ای پشتیبانی می کند. اگرچه به صورت بومی از برنامه نویسی شی گرا پشتیبانی نمی کند، می توانید مفاهیم OOP را با استفاده از انواع داده های داخلی Rust پیاده سازی کنید.
کپسوله سازی در Rust
کپسوله سازی مستلزم سازماندهی کد در واحدهای مستقل است که جزئیات داخلی را پنهان می کند و در عین حال یک رابط عمومی را برای تعامل خارجی برای به حداقل رساندن پیچیدگی و بهبود قابلیت نگهداری کد در معرض دید قرار می دهد.
می توانید کد Rust را با ماژول ها کپسوله کنید. ماژول مجموعه ای از آیتم ها شامل توابع، ساختارها، عددها و ثابت ها است. ماژول های Rust عملکردی را برای گروه بندی و تعیین مرزهای بین بخش های یک برنامه ارائه می دهند.
استفاده از ماژول ها برای کپسوله کردن داده ها و توابع
می توانید یک ماژول را با استفاده از کلمه کلیدی mod و به دنبال آن یک نام تعریف کنید:
mod my_module {
// module items go here
}
شما می توانید ماژول ها را به صورت سلسله مراتبی با قرار دادن اعلان های آنها سازماندهی کنید:
mod parent_module {
mod my_module {
// module items go here
}
}
سپس میتوانید به ماژولهای تودرتو با سلسله مراتب کامل مراجعه کنید، و هر ماژول را با یک دو نقطه از هم جدا کنید، به عنوان مثال، parent_module::my_module.
بهطور پیشفرض، موارد درون ماژولها خصوصی هستند و فقط برای کدگذاری در همان ماژول قابل دسترسی هستند. اما میتوانید با استفاده از کلمه کلیدی pub، ماژولها را عمومی کنید:
mod my_module {
pub fn my_function() {
// function body goes here
}
}
سپس می توانید از قسمت های دیگر برنامه خود به my_function دسترسی پیدا کنید.
استفاده از صفات برای تعریف رفتارها
راه دیگری که Rust امکان کپسوله شدن را فراهم می کند، استفاده از صفات است. صفات رفتارهایی را تعریف میکنند که تیپها میتوانند پیادهسازی کنند و اطمینان حاصل کنند که انواع مختلف با یک رابط مطابقت دارند.
pub trait Printable {
fn print(&self);
}
pub struct MyType {
// struct fields here
}
impl Printable for MyType {
fn print(&self) {
// implementation here
}
}
صفت Printable یک متد چاپ دارد و ساختار MyType با اجرای روش چاپ، صفت Printable را پیاده سازی می کند.
با استفاده از ویژگی ها، می توانید اطمینان حاصل کنید که هر نوع که ویژگی Printable را پیاده سازی می کند، دارای روش چاپ است. این در هنگام کار با کدهای عمومی که نیاز به تعامل با انواع مختلف با یک رفتار مشترک دارند مفید است.
ارث در رست
وراثت به شما امکان می دهد یک کلاس را بر اساس کلاس دیگری تعریف کنید. زیر کلاس خصوصیات و روش های والد خود را به ارث می برد.
در Rust، شما تشویق میشوید که از ترکیب به جای وراثت استفاده کنید. ترکیب فرآیندی است برای ایجاد اشیاء جدید با ترکیب اشیاء موجود. به جای ایجاد یک کلاس جدید که عملکرد را از کلاس پایه به ارث می برد، می توانید یک ساختار جدید ایجاد کنید که حاوی نمونه ای از ساختار پایه و فیلدهای آن باشد.
ایجاد انواع جدید با ترکیب انواع موجود
شما از enums و struct ها برای ایجاد انواع جدید استفاده خواهید کرد. Enum ها برای انواع با مقادیر محدود مفید هستند و ساختارها می توانند چندین فیلد را نگه دارند.
شما می توانید یک نوع enum برای انواع مختلف حیوانات ایجاد کنید.
enum Animal {
Cat,
Dog,
Bird,
// ...
}
از طرف دیگر، می توانید یک ساختار حاوی فیلدهایی برای هر نوع حیوان ایجاد کنید. ساختارها می توانند enum و انواع دیگر را نگه دارند.
struct Animal {
name: String,
age: u8,
animal_type: AnimalType,
}
enum AnimalType {
Cat,
Dog,
Bird,
// ...
}
ساختار Animal مقادیری از نوع AnimalType را در خود دارد.
میتوانید از ویژگیها برای پیادهسازی وراثت استفاده کنید و بدون ایجاد نوع جدید، رفتار را به یک نوع اضافه کنید.
trait Fly {
fn fly(&self);
}
در اینجا نحوه اجرای ویژگی Fly برای انواع مختلف آمده است.
struct Bird {
name: String,
wingspan: f32,
}
impl Fly for Bird {
fn fly(&self) {
println!("{} is flying!", self.name);
}
}
struct Plane {
model: String,
max_speed: u32,
}
impl Fly for Plane {
fn fly(&self) {
println!("{} is flying!", self.model);
}
}
ساختارهای Bird and Plane ویژگی Fly را پیاده سازی کرده و رشته ها را با Println چاپ می کنند! کلان.
شما می توانید روش fly را در هر دو ساختار بدون دانستن نوع خاص آنها فراخوانی کنید.
fn main() {
let bird = Bird {
name: String::from("Eagle"),
wingspan: 2.0,
};
let plane = Plane {
model: String::from("Boeing 747"),
max_speed: 900,
};
let flying_objects: Vec<&dyn Fly> = vec![&bird, &plane];
for object in flying_objects {
object.fly();
}
}
تابع اصلی نمونههای Plane و Bird را نشان میدهد. بردار flying_objects بردار نمونه های شی است و حلقه for از بردار عبور می کند و متد fly را روی نمونه ها فراخوانی می کند.
اجرای چند شکلی در زنگ
یک کلاس یا نوع چند شکلی است اگر چندین نوع یک رابط را نشان دهند. از آنجایی که صفات عملکردی را برای تعریف رفتارها در Rust فراهم می کند، در حالی که یک رابط مشترک برای نوشتن کدهای عمومی ارائه می دهد، می توانید از Traits برای پیاده سازی چندشکلی استفاده کنید.
در اینجا یک ویژگی به نام Drawable وجود دارد که رفتار رندر اشیاء روی صفحه را مشخص می کند:
trait Drawable {
fn draw(&self);
}
انواعی که ویژگی Drawable را پیاده سازی می کنند می توانند به تابع draw دسترسی داشته باشند.
struct Rectangle {
width: u32,
height: u32,
}
impl Drawable for Rectangle {
fn draw(&self) {
// Render the rectangle on the screen
}
}
می توانید کدهای عمومی بنویسید که اشیایی را ترسیم می کند که ویژگی Drawable را پیاده سازی می کنند.
fn draw_object<T: Drawable>(object: &T) {
object.draw();
}
تابع draw_object یک نوع عمومی T را به عنوان ورودی می گیرد که صفت Drawable را پیاده سازی می کند و متد draw را روی صفت فراخوانی می کند. اشیاء مختلف می توانند ویژگی Drawable را پیاده سازی کنند و به عملکرد دسترسی داشته باشند.
T
پیاده سازی انتزاع در زنگ
Abstraction یک مفهوم OOP است که در آن کلاس ها و رابط ها برای اشیاء و انواع مشخص قابل دسترسی هستند. شما می توانید انتزاع را در Rust با ویژگی ها پیاده سازی کنید.
در اینجا یک ویژگی مثال برای پخش کننده رسانه آورده شده است:
trait Media {
fn play(&self);
}
ساختارها و فهرستهایی که ویژگی رسانه را پیادهسازی میکنند باید یک پیادهسازی برای روش بازی ارائه کنند.
struct Song {
title: String,
artist: String,
}
impl Media for Song {
fn play(&self) {
println!("Playing song: {} by {}", self.title, self.artist);
}
}
ساختار Song با ارائه یک پیادهسازی برای روش play که پیامی را با فیلدهای ساختار آهنگ در کنسول چاپ میکند، ویژگی رسانه را پیادهسازی میکند.
fn main() {
// Create an instance of the Song struct
let song = Song {
title: String::from("Bohemian Rhapsody"),
artist: String::from("Queen"),
};
// Call the play method on the song instance
song.play();
}
متغیر آهنگ نمونه ای از ساختار Song است و متغیر می تواند به متد play دسترسی داشته باشد و آن را فراخوانی کند.
سازماندهی کد زنگ آسان است
برنامه نویسی شی گرا به سازماندهی کد کمک می کند. به لطف سیستم ماژول Rust، می توانید به راحتی کد Rust خود را سازماندهی کنید، در حالی که مفاهیم OOP را برای برنامه خود پیاده سازی می کنید تا کد خود را منظم، قابل مدیریت و بصری نگه دارید.