برنامه نویسی به زبان Rust برای توسعه دهندگان جاوا
شنبه 28 اسفند 1400برنامه نویسی به زبان Rust شباهت زیادی به زبان جاوا دارد، ما در این مطلب قصد داریم بیشتر درباره برنامه نویسی به زبان Rust برای توسعه دهندگان جاوا صحبت کنیم.
پیش از آن که بخواهیم درباره برنامه نویسی به زبان Rust توسط توسعه دهندگان جاوا صحبت کنیم اجازه دهید تا کمی بیشتر با این زبان برنامه نویسی آشنا شویم. Rust یکی از زبان های برنامه نویسی جدید است که تعداد توسعه دهندگان آن روز به روز در حال افزایش است. زبان برنامه نویسی Rust یک زبان برنامه نویسی جدید است که در سال 2010 معرفی شد و بی سر و صدا کار خود را ادامه داد تا این که به علت عملکرد بی نظیری که دارد و سینتکس و ویژگی های امنیتی که ارائه می دهد امروزه توجه زیادی را در دنیای برنامه نویسی به خود جلب کرده است. اگر شما هم یک توسعه دهنده جاوا هستید به لطف شباهت این دو زبان برنامه نویسی می توانید همین حالا این زبان را بیاموزید.
برنامه نویسی به زبان Rust
طبق نظرسنجی هایی که در سایت استک آور فلو صورت گرفته است زبان برنامه نویسی Rust در لیست محبوب ترین و پرکاربردترین زبان های برنامه نویسی صعود کرده است و علاوه بر این در میان توسعه دهندگان به عنوان دوست داشتنی ترین زبان برنامه نویسی نیز شناخته شده است. اگر شما هم تجربه ای در زمینه برنامه نویسی به زبان جاوا دارید احتمالا برنامه نویسی به زبان Rust برای شما بسیار ساده خواهد بود و می توانید کار کردن با این زبان برنامه نویسی را به سرعت بیاموزید.
سینتکس زبان برنامه نویسی Rust
دقیقا مانند زبان برنامه نویسی جاوا زبان Rust نیز یک زبان کامپایل شده است. این زبان به LLVM spec کامپایل می شود که دقیقا ماشبه JVM می باشد و به شما اجازه می دهد تا خروجی خود را در انواع پلتفرم ها به راحتی اجرا کنید. علاوه بر این زبان Rust دقیقا مشابه جاوا از خانواده زبان سی است و سینتکس آنها تا حدود زیادی مشابه یکدیگر است. به عنوان یک برنامه ساده از این زبان برنامه نویسی مثال زیر را در نظر بگیرید:
fn main() {
println!("Hello, InfoWorld!");
}
دقت داشته باشید که در این جا نیز یک تابع ()main وجود دارد که دقیقا مشابه نقطه ورود زبان برنامه نویسی جاوا است.
توابع در برنامه نویسی به زبان Rust
توابع در برنامه نویسی به زبان Rust از اهمیت زیادی برخوردار هستند و شما می توانید آنها را در هر جایی از کدهای خود تعریف کنید. یک نکته جالب در این زبان این است که شما می توانید یک تابع را داخل تابع دیگری تعریف کنید و به اصطلاح از توابع تودرتو در برنامه نویسی به زبان Rust استفاده کنید. این موضوع برخلاف جاوا است و در زبان جاوا چنین چیزی امکان پذیر نیست. در زبان جاوا همیشه توابع به عنوان متدهایی روی اشیا تعریف می شوند( به جز مواقعی که قصد استفاده از lambda ها را دارید). به عبارت دیگر می توان گفت در زبان برنامه نویسی جاوا همه چیز یک شی است ولی در زبان برنامه نویسی Rust این طور نیست.
fn main() {
println!("Hello, world!");
fn function2(){
println!("Hello InfoWorld");
}
function2();
function3();
}
fn function3() {
println!("Hello again.");
}
مقادیر برگشتی ضمنی در زبان Rust
برخلاف زبان برنامه نویسی جاوا، Rust به شما اجازه می دهد تا یک کلمه کلیدی را در انتهای تابع برگردانید. عبارت نهایی در تابع به طور خودکار به عنوان مقدار برگشتی در نظر گرفته می شود. دقت داشته باشید که برای انجام این کار شما باید سمیکالون را از انتهای عبارت آخر بردارید.
Lambdas در زبان Rust
دقیقا مانند جاوا زبان Rust نیز برای پشتیبانی از کد نویسی فانکشنال از lambda پشتیبانی می کند. البته باید دقت داشته باشید که سینتکسی که در این دو زبان مورد استفاده قرار می گیرد با یکدیگر متفاوت است اما اگر شما با زبان برنامه نویسی جاوا آشنا باشید اصلا سخت نیست که عملکرد آن در برنامه نویسی به زبان Rust را نیز به خوبی درک کنید. قطعه کد زیر به شما نشان می دهد که چگونه از تابع ()map برای ایجاد مجموعه ای از رشته ها با حروف بزرگ استفاده کنید. همانطور که می توانید مشاهده کنید نحوه انجام این کار تقریبا مانند زبان جاوا است:
// Rust
fn main() {
let animals = ["dog", "badger", "quokka"];
let result = animals.iter().map(|value| value.to_uppercase());
for animal in result {
println!("Uppercased: {}", animal);
}
}
نکته ای که باید درباره قطعه کد بالا به آن دقت کنید این است که تابع ()map یک آرگومان دو بخشی را دریافت می کند. قسمت اول یک متغیر در داخل کاراکترهای pipe می باشد که با |value| نشان داده شده است. این بخش در واقع متغیری را تعریف می کند که به عنوان handle در هر آیتم مورد استفاده قرار می گیرد. بخش دوم در واقع یک عملیات برای اجرا شدن است که در این مثال ما آن را ()to_uppercase نام گذاری کرده ایم. این عملیات در واقع روی هر یک از عناصر موجود در داخل یک آرایه اجرا می شود.
توجه داشته باشید که دقیقا مانند زبان برنامه نویسی جاوا در برنامه نویسی به زبان Rust نیز lambdas در واقع بسته هایی هستند که وضعیت بلوک اطراف را نگهداری می کنند. به عبارت دیگر می توان گفت آنها به context متغیری که در حال اجرای آن هستند دسترسی دارند.
اشیا در زبان Rust با struct نشان داده می شوند
نگاهی به قطعه کد زیر بیندازید که کلمه کلیدی struct را برای شما تعریف می کند. یک struct که در واقع مخفف شده کلمه structure به معنای ساختار است به شما اجازه می دهد تا یک ظرف برای داده های خود تعریف کنید، درست مانند کاری که کلاس ها در زبان برنامه نویسی جاوا برای شما انجام می دادند:
struct Animal {
name: String
}
fn main() {
let dog = Animal{
name: String::from("Shiba")
};
println!("{}", dog.name);
}
شما اعضای داخل یک struct را در داخل آکولادهای آنها تعریف می کنید. این متغیرها در واقع نقش متغیرهای عمومی را در کلاس های جاوا ایفا می کنند.
توجه داشته باشید در خطی که شما متغیر dog را تعریف کرده اید نیازی به فراخوانی کلمه کلیدی جدید نیست. این یکی از مهمترین مزایای برنامه نویسی به زبان Rust به شمار می آید.
در مرحله بعد شما باید توجه داشته باشید که متغیر name در زمان ایجاد یک رشته با یک مقدار مشخص تنظیم شده است. این کار از طریق فراخوانی متد داخلی String.from با استفاده از عملگر مرجع دو نقطه یا double-colon قابل انجام است.
نکته آخری که باید به آن توجه داشته باشید این است که دقیقا مانند زبان جاوا در برنامه نویسی به زبان Rust نیز از عملگر نقطه برای دسترسی به فیلد Name در شی dog استفاده کرده ایم.
متدها در برنامه نویسی به زبان Rust
یکی از نکات مهمی که در برنامه نویسی به زبان Rust و در زمان استفاده از structها باید بدانید این است که شما می توانید توابع را به struct ها اضافه کنید و این توابع دقیقا به همان شکلی که متدها در کلاس های جاوا عمل می کردند برای شما کار می کنند. به عنوان مثال برای اضافه کردن متد ()speak به Animal struct که در بخش قبلی تعریف کردیم می توانیم از کلمه کلیدی impl به شکل زیر استفاده کنیم:
impl Animal {
fn speak(&self) {
println!("{}", self.name);
}
}
Impl در واقع مخفف شده عبارت implementation به معنای پیاده سازی است. در این قطعه کد ما ابتدا Animal struct را تعریف کردیم. در ادامه یک متد speak تعریف کردیم که یک آرگومان را دریافت می کند. آرگومان ما در واقع یک &self pointer خاص است (توجه داشته باشید که در زبان برنامه نویسی Rust علامت $ به این معناست که آرگومان ما از نوع رفرنس می باشد). نکته دیگری که باید به آن دقت داشته باشید این است که این پوینتر ویژه شباهت زیادی به کلمه کلیدی this در زبان برنامه نویسی جاوا دارد که با استفاده از آن می توانستیم به یک شی اشاره کنیم.
حال اگر ()dog.speak را فراخوانی کنید مشاهده خواهید کرد که نام شی فعلی به عنوان خروجی برای شما چاپ می شود که در این مثال Shiba خواهد بود.
Mutability یا تغییر پذیری در زبان برنامه نویسی Rust
از جمله جالب ترین نکاتی که درباره برنامه نویسی به زبان Rust وجود دارد (برای افرادی که در زمینه برنامه نویسی به زبان جاوا تجربه دارند) قابلیت تغییر ناپذیری پیش فرض متغیرهاست. به طور خلاصه می توان گفت زمانی که شما یک متغیر را در زبان برنامه نویسی Rust تعریف می کنید به صورت پیش فرض غیرقابل تغییر خواهد بود و اگر برای تغییر دادن مقدار آن تلاش کنید یک خطا دریافت خواهید کرد.
در برنامه نویسی به زبان Rust برای ایجاد متغیرهایی که قابل تغییر باشند باید از کلمه کلیدی mut استنفاده کنید ولی باید به خاطر داشته باشید که mut تنها می تواند در یک زمان و توسط یک مرجع مورد استفاده قرار گیرد. نکته دیگری که باید به یاد داشته باشید این است که این زبان برنامه نویسی به میزان زیادی به حفظ امنیت کدها اهمیت می دهد. به همین علت است که این قابلیت از خطاهای مربوط به اصلاح همزمان که در زبان برنامه نویسی جاوا مشاهده میشد نیز جلوگیری می کند.
قطعه کد زیر نشان می دهد که چگونه شی dog را قابل تغییر کرد و در ادامه یک نامه جدید را به آن اختصاص داد:
let mut dog = Animal{
name: String::from("Shiba")
};
dog.name = String::from("Suki");
println!("{}", dog.name);
نکته مهم در این قطعه کد این است که کلمه کلیدی mut در زمان تعریف متغیر اضافه شده است.
Type inference در برنامه نویسی به زبان Rust
در برنامه نویسی به زبان Rust همیشه نیاز نیست که به کامپایلر بگویید دقیقا چه نوع متغیری را تعریف می کنید. این مسئله برای توسعه دهندگانی که در حوزه برنامه نویسی به زبان جاوا تجربه دارند ممکن است کمی عجیب به نظر برسد چرا که در این زبان به هیچ وجه چنین امکانی وجود ندارد. به عنوان مثال در قطعه کد زیر کامپایلر می تواند به درستی نوع عدد صحیح را استنباط کند:
let number1 = 10;
let number2 = 10;
println!("{}", number1 * number2);
قابلیت Shadowing و نام متغیرها در برنامه نویسی به زبان Rust
یکی دیگر از ویژگی های زبان برنامه نویسی Rust که ممکن است برای توسعه دهندگان جاوا عجیب به نظر برسد قابلیتی است که به آن shadowing گفته می شود. در اصل این قابلیت به این معناست که شما به جای این که یک متغیر را به عنوان یک متغیر تغییر پذیر تعریف کنید می توانید یک mask در بالای آن با همین نام ایجاد کنید و از آن استفاده کنید.
این یک نوع تغییر پذیری یک باره در متغیر است که فضای جدیدی را برای همان نام متغیر ایجاد می کند. به طور کلی امکان استفاده مجدد از نام متغیر یکسان در برنامه نویسی به زبان Rust متفاوت با جاوا است.
fn main() {
let x = 5;
let x = x + 1;
println!("The value of x is: {}", x); // outputs 6
}
نوع داده tuple در برنامه نویسی به زبان Rust
زبان برنامه نویسی Rust از یک نوع داده به نام tuple پشتیبانی می کند که نوعی متغیر ترکیبی به شمار می آید که دارای نوع مشابهی در زبان برنامه نویسی جاوا نیست. قطعه کد زیر نمونه ای از استفاده از tuple در برنامه نویسی به زبان Rust را به شما نمایش می دهد:
fn main() {
let myTuple = ("Sum", 10, 5);
let (x, y) = myTuple ;
println!("The {} is: {}", x, y + z);
}
در این قطعه کد شما می توانید مشاهده کنید که متغیر myTuple با استفاده از پرانتزهایی که شامل سه مقدار هستند تعریف شده است که این سه مقدار شامل یک رشته و دو عدد صحیح می باشند. این دقیقا نشان دهنده نوع داده tuple است.
همانطور که در خط بعدی این قطعه کد می توانید مشاهده کنید که در برنامه نویسی به زبان Rust این امکان برای شما وجود دارد که مقادیر داخل tuple را به متغیرهای اسکالر تجزیه کنید که برای این کار می توان از کلمه کلیدی let استفاده کرد که مقادیر داخل tuple شما را به سه متغیر X، y و z اختصاص می دهد.
علاوه بر این شما می توانید در برنامه نویسی به زبان Rust به اعضای tuple خود از طریق ایندکس آنها دسترسی داشته باشید. به عنوان مثال tup.0 اولین مقدار موجود در tuple که یک رشته است را برای شما برمی گرداند.
traits و جنریک ها در برنامه نویسی به زبان Rust
در برنامه نویسی به زبان Rust مفهومی با نام traits وجود دارد که تا حدود زیادی شبیه به اینترفیس های fine-grained در زبان برنامه نویسی جاوا است. آنها در واقع تعریف می کنند که یک نوع داده چه ویژگی هایی را با سایر انواع داده به اشتراک می گذارد. به عبارت دیگر می توان گفت traits همان عملکرد انتزاعی مشترک بین انواع داده مختلف به شمار می آیند.
جنریک ها در برنامه نویسی به زبان Rust شباهت زیادی به جنریک های جاوا دارند که از یک براکت برای آدرس دهی انواع داده به صورت کلی و بر پایه ویژگی هایی که به اشتراک گذاشته اند استفاده می کنند. در قطعه کد زیر تلاش کرده ایم تا این مفاهیم را به طور خلاصه به شما توضیح دهیم:
pub trait Summary {
fn summarize(&self) -> String;
}
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
fn main() {
let tweet = Tweet {
username: String::from("dog_post"),
content: String::from("A Shih Tzu is smaller than a Lurcher",
),
reply: false,
retweet: false,
};
println!("1 new tweet: {}", tweet.summarize());
}
در این جا کلمه کلیدی trait برای تعریف یک ویژگی Summary استفاده می شود که برای هر یک از انواع داده به صورت جداگانه پیاده سازی می شود که متغیرهای مربوط به آنها شامل NewsArticle و Tweet هستند که با استفاده از کلمه کلیدی impl پیاده سازی شده اند. همانطور که مشاهده می کنید این روش شباهت زیادی به اینترفیس ها در زبان برنامه نویسی جاوا دارد به جز این مورد که در زبان جاوا یک اینترفیس به جای تعریف تکه ای متدها کل سطح کلاس را تعریف می کند.
- Java
- 1k بازدید
- 1 تشکر