توی یکی دیگه از مقالات راست میخوایم دو بخش پنج و شیش رو با هم بخوونیم. پس با من همراه باشید تا با شما چند چیز رو مرور کنم.
ابتدا میخوایم با متود ها توی راست آشنا بشیم.
در زیر خیلی ساده متود ها رو توضیح دادیم:
۱. متود ها فانکشن هایی هستن که با آبجکت ها کار میکنن\
۲. متود ها دسترسی به داده های آبجکت ها رو دارن\
۳. متود ها با کلیدواژه self
به داده های آبجکت ها دسترسی پیدا میکنن\
۴. متود ها با کلیدواژه impl
پیاده سازی میشن
خب حالا که متوجه شدید متود ها چین بزارید استراکچر ها رو هم توضیح بدیم:
۱. استراکچر ها توی راست یه نوع دیتا تایپ هستن\ ۲. استراکچر ها داده هایی رو با تایپ یا نوع های مختلف رو توی خودشون نگه میدارن
در واقع استراکچر ها فیلد های مختلفی رو دارن و ما میتونیم ازشون استفاده کنیم اما به همین جا ختم نمیشه ماجرای استراکچر ها و استراکچر ها سه نوع هستن، در زیر توضیح داده شده است:
- Tuple structures
- The classic C structures
- Unit structs
به کد زیر توجه کنید
/* A tuple struct */
struct Pair(i32, f32);
/* A struct with two fields */
struct Point {
x: f32,
y: f32,
}
/* A unit struct */
struct Unit;
بر اساس کاری که دارید انجام میدید میتونید از این سه نوع استراکچر استفاده کنید و جلو برید، ما توی این مقاله قراره از نوع دوم استفاده کنیم.
حالا که همه چیز رو متوجه شدید به مثال زیر توجه کنید
struct Point {
x: i32,
y: i32,
}
fn main() {
let point: Point = Point { x: 10, y: 5 };
println!("x: {:?} and y: {:?}", point.x, point.y);
}
خروجی کد بالا
x: 10 and y: 5
در بالا یه استراکچر داریم که دو فیلد با تایپ i32
داره
بعد اومدیم از استراکچری که داریم یه متغیر ساختیم و داده ها رو مقدار دهی کردیم ولی توجه کنید که به جز تایپ مشخص شده یعنی i32
نمیتونیم مقدار دهی کنیم.
بعد به داده های متغیری که ساختیم دسترسی پیدا کردیم و اونا رو چاپ کردیم. اما توجه کنید که ما متودی برای استراکچرمون یا آبجکتمون نداریم!
به مثال زیر توجه کنید
struct Point {
x: i32,
y: i32,
}
impl Point {
fn original() -> Point {
Point { x: 1, y: 1 }
}
fn new(x: i32, y: i32) -> Point {
Point { x: x, y: y }
}
}
fn main() {
let point_one: Point = Point::original();
println!("x: {:?} and y: {:?}", point_one.x, point_one.y);
let point_two: Point = Point::new(10, 5);
println!("x: {:?} and y: {:?}", point_two.x, point_two.y);
}
خروجی کد بالا
x: 1 and y: 1
x: 10 and y: 5
در مثال بالا ما اومدیم برای استراکچری که داریم دو متود رو تعریف کردیم که اسمشون original
و new
هست.\
اگر توجه کنید دیگه ما برای استراکچر Point
متود داریم و میتونیم از متودهامون استفاده کنیم.\
متود اول یعنی original
برای ما یه پوینت رو میسازه و برمیگردونه با مقدار ایکس و ایگرگ یک.\
متود دوم یعنی new
از ما دو مقدار رو میگیره و اونا رو با ایکس و ایگرگ ست میکنه و یه پوینت میسازه و برمیگردونه.
اگر هم توجه کنید دو متود خروجیشون پوینت هست.
حالا میخوایم کمی ماجرا رو سخت کنیم و بیشتر یادبگیریم به مثال زیر توجه کنید
#[derive(Debug)]
struct Number {
x: i32,
}
impl Number {
fn print_min_y(&mut self, x: i32) -> i32 {
self.x -= x;
return self.x;
}
}
fn main() {
let number: &mut Number = &mut Number { x: 11 };
println!("number.print_min_y: {:?}", number.print_min_y(1));
number.print_min_y(1);
println!("self.x: {:?}", number.x);
println!("number: {:?}", number);
}
خروجی کد بالا
number.print_min_y: 10
self.x: 9
number: Number { x: 9 }
نکته: عبارت #[derive(Debug)]
یک attribute
هست.
ممکنه طولانی بودن کد بالا باعث شده باشه که فکر کنید ماجرا خیلی سخت هست اما با هم دیگه تحلیلش میکنیم.\
اول از همه این رو بگیم که با attribute
ها در آینده آشنا میشیم و نگران این موضوع نباشید.
ما یه استراکچر با نام Number
تعریف کردیم که یه فیلد داره و اون فیلد تایپش i32
هست و اومدیم یه متود براش تعریف کردیم و این متود یه ورودی رو میگیره و با اون ورودی یه محاسباتی رو با فیلدی که داریم انجام میده و فیلد ایکس
رو بهمون برمیگردونه.\
اگر هم توجه کنید وقتی number
خالی رو چاپ میکنیم و ازش چیزی نمیخوایم استراکچری که ساخته شده با فیلد و مقادیری که داره رو برامون چاپ میکنه.
در بخش شیشم هم میخوایم با کلوژر ها
توی راست آشنا بشیم
کلوژر ها مبحثی جالب توی برنامه نویسی هستن و توی راست کلوژر ها خیلی به روبی و اسمال تاک نزدیک هست.\
کلوژر های راست در واقع فانکشن های آنانیموس هستن یا همون anonymous functions
اگر هم جاوا کار کرده باشید با مبحث فانکشن های آنانیموس آشنا هستید.
کلوژر ها فانکشن هایی هستن که محیط محدود شده ای دارن بر خلاف خوده فانکشن هایی که داریم یعنی چی ؟ برای درک بهتر به مثال زیر توجه کنید
fn main() {
fn function (i: i32) -> i32 { i + i }
let closure_annotated = |i: i32| -> i32 { i + i };
let closure_inferred = |i | i + i ;
let i = 1;
println!("function: {}", function(i));
println!("closure_annotated: {}", closure_annotated(i));
println!("closure_inferred: {}", closure_inferred(i));
let one = || 1;
println!("closure returning one: {}", one());
}
خروجی کد بالا
function: 2
closure_annotated: 2
closure_inferred: 2
closure returning one: 1
دیدید که چطور ما توی راست کلوژر ها رو میسازیم و چطور کار میکنن و میتونیم به عنوان فانکشن ازشون استفاده کنیم اما در محیطی محدود تر از فانکشن هایی که واقعا تعریف میشن.
امیدوارم از این مقاله هم لذت کافی رو برده باشید.