در Rust، پیاده سازی فانکشنها ( implementation block )
به ما اجازه میدهد تا عملکردی را برای یک type مشخص، تعریف کنیم که ایجاد روشها و توابع مرتبط برای انواع دادههای سفارشیمان را ممکن میسازد. در این مقاله، نحوهی استفاده از implementation block را برای تعریف متدها و توابع مرتبط در Rust، با استفاده از ساختار Product به عنوان مثال، بررسی خواهیم کرد.
ابتدا، بیایید یک struct محصول را با فیلدهای زیر تعریف کنیم:
struct Product {
name: String,
price: f32,
in_stock: bool,
}
پیاده سازی اجرای روش محاسبه مالیات فروش برای struct product
در ادامه بیایید تابع catalog_sales_tax را به عنوان روشی برای ساختار Product، با استفاده از یک implementation block اضافه کنیم.
impl Product {
fn calculate_sales_tax(&self) -> f32 {
self.price * 0.1
}
}
در این مثال، از کلمهی کلیدی Self، برای ارجاع به نمونه محصولی که این تابع با آن فراخوانی میشود، استفاده میشود؛ به عبارت دیگر وقتی از Self استفاده میکنید، یعنی دارید خود Product را صدا میزنید و به فیلدهای آن دسترسی دارید.
استفاده از متد در تابع اصلی
اکنون میتوانیم یک نمونه محصول را ایجاد کنیم و از روش محاسبه مالیات استفاده کنیم:
fn main() {
let book = Product {
name: String::from("Book"),
price: 28.85,
in_stock: true,
};
let sales_tax = book.calculate_sales_tax();
println!("Sales tax: {}", sales_tax);
}
انواع مختلف Self
Immutable borrow (در مواردی استفاده میشود که میخواهید به سادگی از فیلدهای خود بدون تغییر چیزی استفاده کنید):
fn calculate_sales_tax(&self) -> f32 {
self.price * 0.1
}
Mutable borrow (در مواردی که میخواهید فیلدهای خود را تغییر دهید استفاده میشود):
fn set_price(&mut self, price: f32) {
self.price = price;
}
Owned form (مالکیت نمونه به متد منتقل شده و نمونه در پایان متد حذف میشود و دیگر معتبر نیست):
fn buy(self) {
let name: String = self.name;
println!("{} was bought", name);
}
Associated Functions
Associated functions از کلمه کلیدی self استفاده نمیکنند و با استفاده از سینتکس :: فراخوانی میشوند. با این حال، هنگام فراخوانی توابع مرتبط در متدهایی که از self استفاده میکنند، '.' بجای آن از سینتکس '::' استفاده میشود:
impl Product {
fn new(name: String, price: f32) -> Product {
Product {
name,
price,
in_stock: true,
}
}
}
اکنون، میتوانیم یک نمونه محصول را با استفاده از تابع جدید مرتبط ایجاد کنیم:
fn main() {
let book = Product::new(String::from("Book"), 30.0);
}
در این مقاله، بررسی کردیم که چگونه Implementation Blocks در Rust به ما اجازه میدهند تا عملکردی را برای انواع دادههای سفارشی، مانند روشها و توابع مرتبط تعریف کنیم. با درک اشکال مختلف self و نحوهی استفاده از آنها، میتوانید روشهای قدرتمند و انعطاف پذیری را برای انواع دادههای سفارشی خود در Rust پیاده سازی کنید.