Latest Posts from Rust for Python developers (@pyrust) on Telegram

Rust for Python developers Telegram Posts

Rust for Python developers
Rust programming language for python developers

یک توسعه دهنده پایتون هستم که سعی میکنم rust یاد بگیرم.
تو این مسیر منابع و نظرات شخصی خودم رو با آیندگان هم به اشتراک میذارم

اگر به هوش مصنوعی و پایتون علاقه دارید به کانال :
@pytens
@pyhints
سر بزنید.
1,740 Subscribers
13 Photos
2 Videos
Last Updated 06.03.2025 22:23

Similar Channels

Programming Resources
22,063 Subscribers
Python BackendHub
7,083 Subscribers
Deep Time
3,717 Subscribers

The latest content shared by Rust for Python developers on Telegram

Rust for Python developers

26 Feb, 21:20

723

توی ۷-۸ روز اخیر پروژه لینوکس کرنل یک مینتینرهایی رو داشت از دست میداد که نباید (لاشخورها هم نشسته بودن رو هوا بزنند‌ها؛ ویندوز و مک) بگذریم. کار به جایی رسید که اومدن برای این موضوع قانون گذاری کردند.
https://rust-for-linux.com/

مثل سری قبلی نظرات شخصی هم داشت وارد می‌شد؛ که بعضی مینتینرها داشتن می‌کفتند نمی‌خواند کد Rust ببینند و Accept کنند چون ممکنه باعث باگ بشه؛ توسعه دهنده‌های Rust که توی برخی موارد مینتینر بخش‌های دیگری از کرنل هم هستند با حفظ سمت داشتن می‌کفتند که بابا ما این کد Rust رو برای شما زدیم چون باگهای مموری شما مارو سرویس کرده و همین بحث که ما اضاقه نمی‌کنیم چون ممکنه باعث باگ بشه؛ اوناهم که خب چون باگ داری و توان فیکس ندارید ما کد دونیت کردیم و این شده بود یک loop تا قانون اضافه شد.

الان مشخص شده همین قانون هم خودش یک سلسله ایمیلی بوده (راستی همه‌ی ایمیل‌های بحث‌های توسعه کرنل لینوکس بطور کامل روی kernel.org هست؛ بعله حتی فحش ناموسی‌هایی که به دولوپر تازه‌کارا سر اشتباهاتشون دادن؛ اکثرا هم کار خود لینوس هستا؛ حالا ما اینجا به دولوپر میگیم بیشتر دقت کن گریه می‌کنه میره خونشون یا با اولیاش میاد)

داستان اینه لینوس شخصا می‌دونه که Rust باید بیاد توی کرنل چون باعث پیشرفت می‌شه و از رقیبا عقب نمیوفته ولی بعضی از مینتینرهای قدیمی که نمی‌تونند Rust رو یاد بگیرند دارند احمقانه باهاش مبارزه می‌کنند. (از حق نگذریم حدود ۱۰٪ هم حق دارند و منطقی توضیح می‌دهند که باید توی فلان بخش فعلا روی C بمونیم)؛ یک گروه دیگه هم هستند منطقی‌های C بلد که میگن کدهای اصلی که روی C نوشته شده بذاریم باشه (بالای ۳۰ میلیون خط کد هست کرنل) ولی کدهای جدید و ... رو باید بریم روی Rust اگر کسی توی دنیای Rust گردن نگرفت با C میزنیم و مثال هایی هم هست که توسعه Rust هفته‌ها جلوتر از C بوده مخصوصا برای سخت‌افزارهای جدید چون باگ کمتر داشته و کد زدن توی Rust برای سخت‌افزار به مراتب سریعتر از C هست؛ و خب بنظرم صحبت‌های این دسته ۱۰۰٪ منطقی هست ولی با همینم مخالفت می‌کنند.

دسته دیگری هم هستن که با دیتا صحبت می‌کنند؛ که بیشترین مشکل ما توی باگ‌هایی که باعث نفوذ به سرور شده توی 15+ سال قبل همش مربوط به مدیریت مموری توی C و خطای دولوپر بوده (اینا بهترین دلوپرهای دنیا هستنا) پس منطقی هست که سعی کنیم بریم سراغ Rust بدون شک و تردید در آینده باید این اتفاق بیوفته اینا با اینکه توسعه دهنده Rust نیستند ولی به اندازه تیم توسعه لینوکس کرنل با Rust موافق اضافه شدن Rust به کرنل هستند و کامل حمایت می‌کنند.

دعوا شدیدا بالا گرفته و نظرات شخصی خیلی خیلی داره روی کرنل لینوکس و البته آینده کاربرهاش تاثیر میذاره و بازم من با سخنرانی حذف شده یکی از maintainer های قبلی اشاره می‌کنم که این مزمون رو داشت (بعد از۳۵ دقیقه کل‌کل توی سخنرانیش) :

توی تیم Kernel فسیل‌های احمق و خودخواهی هستند که چون شعور و قدرت یادگیری زبان جدید (Rust) رو ندارند حاضرند این دستاورد (منظور پیشرفت‌های لینوکس بعد از سال‌ها و ورود بیشترش به دنیای دسکتاپ هست) رو با خودشون به نابودی ببرند.

این توی یکی از سخنرانی‌ها بود؛ موج اول خدافظی از Linux Rust Kernel رو بهمراه داشت؛ سخنرانی بعد ازین بحث تموم شد و ویدئو این بخش هم از یوتیوبشون حذف شد (اون روز بحث کردیم راجبش).

فعلا شخص لینوس تروالدز وارد شده و بنظر می‌رسه خودش موضوعات مربوط به Rust رو گردن بگیره که بسیار بسیار خوشحال کننده هست ولی کاش زودتر بود.

پینوشت:

کدی که سرش این دعوا اخیر بوجود اومد تایید شده و maintainer مخالف از این بخش (کل نه‌ها فقط همین بخش) حذف شد؛ دلیلشم این بود که مخالفتش غیر منطقی بوده (خود لینوس تروالدز این کدپ رو تایید کرده)
Rust for Python developers

23 Feb, 08:35

1,041

Rust 1.85.0:

بهترین چیزی که اضافه شده بنظرم؛ async closure هست.

let mut vec: Vec<String> = vec![];

let closure = async || {
vec.push(ready(String::from("")).await);
};


این موضوع خیلی کار رو نسبت به async block ها راحت‌تر می‌کنه دیگه درگیری ownership و ... رو نداره.

Rust edition 2024
هم همزمان منتشر شده؛ که یک سری رزرو جدید و ... داشته

Rust Blog

نظرشخصی:
بنظرم هرچی بیشتر جلو میریم کد زدن توی Rust راحت‌تر و تمیزتر خواهد شد.
Rust for Python developers

17 Feb, 16:08

1,303

#5min_Rust

درنهایت نکات مهمی که راجب Stack باید یادتون بمونه :

۱- سرعت بالاتری داره نسبت به heap؛ چون برای دیتاهاش نیازی نداره به سیستم عامل بگه براش حافظه پیدا کنه ( system call کمتری داره )
۲- داده‌هایی می‌تونند روی Stack قرار بگیرند که از قبل سایزشون مشخص باشه؛ یعنی بدونیم چقدر فضای حافظه رو نیاز دارند.
۳- نمی‌تونیم از یک تابع به داده‌ای داخل تابع دیگر که روی استک هست اشاره کنیم؛ چون همونطور که دیدیم وقتی اجرا اون بخش کد تموم بشه تمام مقادیر از Stack حذف میشه و ما می‌مونیم و اشاره‌گر به خانه حافظه‌ای که یا خالی هست یا نباید بهش اشاره می‌شده و این موضوع امن نیست.
Rust for Python developers

17 Feb, 15:48

1,231

#5min_Rust

خب توی این مثال؛ اول از همه یک مقدار حافظه از Stack به تابع main اختصاص داده می‌شه؛ توی اولین دستور داخل main یک متغییر داریم به اسم a و مقدار 22 که داخل Stack قرار می‌گیره (نوع داده int چون سایزش زمان کامپایل مشخص هست همیشه داخل stack قرار میگیره)

بعد از اون برای بدست آوردن مقدار b باید تابع دیگری صدا زده بشه؛ که اینبار add_one هست و یک فضای اختصاصی روی Stack بهش داده می‌شه؛ و کاری که می‌کنه اینه که ورودی رو +1 می‌کنه و برای کسی که صداش زده برمی‌گردونه پس یک متغییر به اسم i داره که آرگومان ورودی تابع هست و توی استک قرار میگیره و خروجی هم توسط return برای آدرس b توی main ارسال میشه 0x23f توی این مثال؛ توی این بازه که داشتیم روی add_one کار میکردیم پشت صحنه SP هم جابجا شد و بجای اینکه به آخر main روی stack اشاره کنه به انتهای آدرس add_one اشاره میکرد.
وقتی کارمون با تابع add_one تموم شد و مقدارش رو برگردوندیم؛ این بخش از Stack حذف میشه؛ باتمام متغییرها و مقادیری که توی این بخش بود (درک این موضوع به lifetime, ownership, ... کمک می‌کنه پس یادتون بمونه)
و SP دوباره بر میگرده و انتهای main رو نشون میده و b 23 داخل استک main قرار میگیره.

بعد از اون متغییر answer_universe رو داریم؛ این مقدار رو چون می‌خواستیم بمونه و با حذف Stack پاک نشه تصمیم گرفتیم بفرستیمش روی Heap اما یادتون باشه بالاتر گفتم int روی stack جا داره چون سایزش از قبل معلوم هست؛ برای اینکه به زور ببریمش روی Heap از چیزی به اسم Box استفاده می‌کنیم (درآینده راجبش حرف میزنم)

وقتی on_heap صدا زده میشه؛ استک فقط و فقط شامل main هست و add_one حذف شده ازش (توی تصویر نمی‌شد این رو نشون داد) on_heap داخل خودش b رو داره (آپدیت کردن SP یادمون نرفته فقط دوباره توضحیش نمیدم) و b رو میخوایم روی heap بفرستیم پس به سیستم درخواست میدیم یک فضایی به اندازه i32 نوع داده integer 32bit برامون روی heap پیدا کنه و بهمون بده وقتی سیستم این رو پیدا کرد دیتای 42 رو اونجا مینوسه و آدرسش 0x5f21 رو بهمون بر میگردونه و بعد هم که return , ....

بعد از این مرحله تابع on_heap هم از روی stack حذف میشه و فقط main ‌می‌مونه روی main چون answer_universe هنوز به دیتای 42 روی heap نیاز داره پس اون دیتاهم روی heap وجود داره.

در نهایت وقتی این کارها تموم شد (اینجا print, ... نداریم) برنامه بطور کامل اجرا شده و main هم تموم می‌شه و تمام مموری پاک میشه.


پینوشت:
منبع نمونه کد بالا؛ این رو قبلا گذاشته بودم بنظرم خوبه دوباره زیر این پست هم باشه.
Rust for Python developers

17 Feb, 15:21

819

#5min_Rust

تفاوت Stack, Heap, Static در Rust:

اولین نکته اینه که خیلی از دوستان به اشتباه فکر می‌کنند که این ۳ مورد حافظه‌های متفاوتی هست و این مشکل از اینجا میاد که راجب سرعت صحبت می‌شه.

توی تصویر مثال بالا اگر دقت کنید؛ هر ۳ مورد داخل RAM هستند فقط ویژگی‌های مختلفی دارند که بهشون می‌پردازیم:
وقتی شما کد رو اجرا می‌کنید اول یک سری فضا به برخی موارد اختصاص داده می‌شه؛ برای مثال خود دستورالعمل‌های کد شما که توی تصویر سمت چپ Stack هستند؛ این بخش شامل static, global variable و ... هم میشه.
از مثال زدن data type ها پرهیز می‌کنم چون هنوز باهاشون آشنا نشدیم.
بعد از اینکار برای Rust یک فضای 8MB پشت سرهم درخواست داده می‌شه که این فضا بعنوان Stack اصلی توسط برنامه استفاده خواهد شد.
دیفالت 8mb هست برای ترد اصلی و 2mb برای تردهای دیگه توجه کنید که لزوما همون لحظه کل 8mb رزرو نخواهد شد اما برنامه شما تا 8mb دسترسی به استک داره و اگر بیشتر بشه stack overflow رخ میده و برنامه kill میشه.

با ویژگی‌های اصلی استک شروع کنیم و بعد به سراغ مثال بریم:
۱- سرعت؛ توی تصویر دقت کنید؛ یک بخشی بین stack, heap نوشتم Stack Pointer؛ یکی از رجیسترهای CPU وظیفه نگهداری آدرس شروع Stack رو به عهده می‌گیره و هموراه به آدرس انتهایی آخرین دیتای موجود در استک اشاره می‌کنه.

۲- هر نوع داده‌ای که می‌خواد داخل استک قرار بگیره باید سایز مشخصی داشته باشه. در زمان کامپایل باید مشخص بشه چقدر جا می‌خواد.

ترکیب دو مورد بالا باعث میشه که بتونیم خیلی سریع به دیتاهای روی Stack دسترسی بگیریم اما یک محدودیت هم هست؛ Stack مثل بشقاب چینی می‌مونه وقتی روی هم میچینی نمی‌‌تونی از آخر ی دونه رو بکشی بیرون؛ باید به ترتیب از بالاترین بشقاب برداری تا به پایینی (آخری برسی).

مورد بعدی Heap اما داستان متفاوتی داره؛ برخلاف Stack که خودش بصورت خودکار حافظه اختصاص میده و میگیره heap اینطوری نیست و هروقت به این حافظه نیاز داشته باشه باید به سیستم عامل بگه که یک همچین حافظه‌ای لازمه تا سیستم عامل اون میزان رو پیدا کنه و بهش بگه از اینجا به بعد رو می‌تونی استفاده کنی.

توی عکس بالا توی بخش heap خونه‌های قرمز بخش‌های از حافظه‌ هست که برای کارهای دیگه اختصاص داده شده و ما نمی‌تونیم دسترسی بگیریم؛ همین بررسی اینکه کجا رو به ما اختصاص بده باعث میشه سرعت این حافظه کندتر باشه.
پاک کردن داده از Heap هم توسط ownership, borrowing توی Rust مدیریت میشه که بعدا راجبش صحبت می‌کنیم.

توی پست بعدی راجب نمونه کد و جزئیاتش توی تصویر بالا صحبت خواهیم کرد.

پینوشت:
من سعی کردم خیلی ساده توضیح بدم تا کلیات و تفاوت‌های اصلی رو همه متوجه بشوند و از بحث راجب نحوه دقیق عملکرد در اینجا خودداری کردم (باشه برای آینده)
Rust for Python developers

13 Feb, 08:14

1,928

نمیدونم چرا این کتاب رو نخوندم و ندیده بودم (سرفصل‌هاش رو)

بسیار کتاب جذاب و خوبی هست؛ بله درسته با Rust 2018 هست ولی واقعا مهم نیست.
متوجه شدم یکی از دوستانی که توی گوگل دارم؛ تغییر Stack داده از C به Rust ایشون توی تیم کروم بودند.
کلی باهاش صحبت کردم؛ چون توی این مدت بسیار به نوشتن کرنل علاقمند شدم و خودم دارم روش کار می‌کنم (کند پیش میرم چون تسک‌های دیگه دارم ولی پیش میرم.)
ازش خواستم توی این موضوع بهم کمک کنه منابعی که خوندم رو بهش دادم؛ چندتا سوال ازم پرسید (مثل مصاحبه) و بعد این منبع رو بهم داد:
Programming Rust 2nd Edition

خوشحال شدم که همین اول مسیر یکی مشکلاتم رو بهم گفت؛ ناراحت شدم ازینکه با این تجربه چرا این کتاب رو نخوندم؛ دلیلش رو هم می‌دونم.

خیلی سال هست توی دنیای پایتون - هوش مصنوعی بودم؛ توی اون دنیا سرعت تغییراتی که باقی چیزها رو خراب کنه خیلی زیاده (بیش از حد) برای همین منبع ۳ سال قدیمی خیلی به کار نمیاد تازه منابع یادگیری هم خیلی زیاد و راحت در دسترس هست؛ اشتباه کردم با اون دید توی دنیای Rust دنبال منبع گشتم.

حالا اولویتم این کتاب هست؛ تا شنبه بنظرم بتونم ۱۲-۱۳ فصل اول رو بخونم و تمرین کنم.
یا اصطلاح دید یک سری منابع دیگه هم پیدا کردم که زیر این پست میذارم اگر دوست داشتید بررسی کنید.

۱- این از یک دوره اومده که certificate می‌داده برای Rust بنظرم برای مصاحبه خوبه چون تمرینات خوب و سوال جوابای خوبی داره (با اصطلاحات به خوبی آشنا می‌شید)
RustCamp
۲- موارد خیلی مهم مربوط به trait های standard library رو توی این مورد پیدا می‌کنید؛ کسایی که با Rust کمی جدی کد زده باشند می‌دونند که خیلی وقتا باید این موارد رو بشناسی تا برای struct, enum, ... خودت تعریفشون کنی و زندگی رو راحت کنی
Tour of std

۳- از همون نویسنده قیلی این پستش هم خیلی خوبه؛ اشتباهات رایج توی درک Lifetime رو اینجا گفته
Lifetime Misconceptions

۴- از سایت تمرینات راست هم این مورد خیلی خوبه (من تمرین کردن رو از خوندن بیشتر دوس دارم) :
100 Exercises to learn Rust

۵- در نهایت اینم چون از دنیای پایتون اومدم:
Rust-Python interoperability

شخصا به ترتیب با اولویت کتاب توی وقتهای خالی دارم این مورد رو پیش می‌برم.
Rust for Python developers

11 Feb, 15:54

1,253

لحظه نوشتن متن بالا مثال خوبی برای static یادم نیومد.
اما گفتم یکی از استفاده‌هاش برای Singleton هست؛ برای مثال اینجا مطمئن میشم همه تست‌ها فقط یکبار اجازه صدا زدن کد رو دارند.
Rust for Python developers

11 Feb, 13:34

1,355

#5min_Rust

انواع روش‌های لیبل زدن برای مقادیر رو توی این پست بررسی کنیم؛ معمولا این رو با اسم متغییر می‌شناسیم ولی خب توی زبان‌های مثل Rust اسم متغییر کمی گیج کننده هست. چرا ؟

اول با immutable, mutable شروع کنیم (تغییر پذیر و تغییر ناپذیر) :
بصورت پیش‌فرض تمام متغییرهایی که توی Rust تعریف می‌کنیم تغییرناپذیر هستند و برای تعریف یک متغییر از کلید let استفاده می‌شه یک مثال ببینیم:
let channel = "pyrust";

اگر بصورت immutable یک متغییر رو تعریف کنید تا آخر نمی‌تونید مقدارش رو تغییر بدید؛ اما توجه کنید با اینکه زبان Rust زبان Static type هست من توی این مثال type متغییر رو تعریف نکردم (راجب type ها تصمیم گرفتم بعد این پست صحبت کنم چون آموزش ویدئویی نیست و برای مثال زدن روی اون موارد باید این پست خونده می‌شد) فعلا بیاید قبول کنیم که "pyrust" توی مثال بالا از نوع داده اصطلاحا string slice هست. خود کامپایلر انقدر باهوش هست که شما نیازی ندارید این type هارو بهش بگید و می‌تونه خودش حدس بزنه ولی اگر خواستید بصورت دستی بهش تایپ هم بدید :
let channel: &str = "pyrust";

از کلمه let برای تعریف متغییر استفاده می‌شه؛ بعد از اون اسم متغییر میاد که اینجا channel هست و بعد از اون : &str که معلوم می‌کنه این متغییر از چه نوع داده‌ای باید باشه و هست باقیشم که توی همه زبان‌ها یکسان هست.
اما اگر بخوایم یک متغییر تعریف کنیم و به کامپایلر بگیم در طول اجرای برنامه این متغییر اجازه داره مقدارش عوض بشه چطور ؟ فقط کافیه از کلمه کلیدی mut (مختصر شده mutable استفاده کنیم) :
let mut channel: &str = "pyrust";

تنها تفاوت اینه که قبل از اسم متغییر (channel) باید mut رو بذارید.
این موارد رو تست کنید:
fn main() {
let channel = "pyrust";
channel = "pyhints";
println!("Channel is: {}", channel);
}

اگر به ارور کامپایلر (یا rust-analyzer) دقت کنید؛ می‌بینید که علاوه بر اینکه ارور رو بهتون می‌گه راهکار رو هم بهتون نشون میده؛ تستش کنید.
fn main() {
let mut channel = "pyrust";
channel = "pyhints";
println!("Channel is: {}", channel);
}

توی مثال بالا مقداری warning می‌گیرید که اهمیتی نداره فعلا؛ اما حتی وقتی متغییر رو mut بکنید اجازه ندارید نوع داده داخلش رو عوض کنید:
fn main() {
let mut channel = "pyrust";
channel = 1590;
println!("Channel is: {}", channel);
}

این متغییر تا آخر باید از نوع string slice بمونه؛ البته با shadowing می‌شه از همین اسم مجدد استفاده کرد ولی اون موضوع برای آینده هست.

بعد از let به یک کلمه کلیدی دیگه میرسیم به اسم const مخفف constant برای تعریف مقادیر ثابت استفاده می‌شه و حتما هم باید بهشون type رو بدید اولین نکته درباره const در Rust اینه که مقدارش حتما باید قبلا از کامپایل بهش داده بشه.
این یعنی شما نمی‌تونی نتیجه محاسبات یا دیتای ورودی کاربر و ... رو توی const نگهدارید.

const OWNER: &str = "Mo.Abbasi";

fn main() {
let channel = "pyrust";
println!("Channel {channel} owner is {OWNER}");
}

توی این مثال چندتا نکته هست:
اول؛ const می‌تونه بعنوان global variable تعریف بشه؛ خارج از محدوده main. توی چندین scope جا میگیره تابع؛ ماژول و یا گلوبال (راجب scope هم مثال خواهم زد).
دوم؛ همیشه برای اسم constant ها از حروف بزرگ باید استفاده بشه.
سوم؛ println هست که می‌تونم اسم متغییر رو داخل {} بذارم؛ راحتر از موارد قبلی.

در نهایت آخرین مورد static هست؛ مثل const باید تایپ رو بهش بدید؛ مثل let هم mut, immut داره (که البته ۹۹٪ سعی کنید از mut اش استفاده نکنید.) مقدارش می‌تونه در زمان کامپایل یا در زمان initialize کردن برنامه مشخص بشه (مثلا config مربوط به اجرای برنامه‌)
خوبیش اینه که از شروع کار برنامه تا خروج ازش می‌تونید بهش دسترسی داشته باشید اصطلاحاْ liftime اش به اندازه خود پروسس کد اصلی هست.


توی تمام مثال‌های بالا بیشتر تفاوت و استفاده‌ها به lifetime, scope برمی‌گرده اما با همین توضیحات ساده هم شما باید بتونید تشخیص بدید چه زمانی از کدوم استفاده کنید.
نکته بعدی نحوه مصرف مموری هست؛ این رو فقط بعنوان رفرنس میذارم چون جلوتر بررسی خواهیم کرد (پست‌های آینده)

let: Stack/Heap depending on the data type.
const: Compiler inline / memory location.
static: Static memory region.
Rust for Python developers

10 Feb, 16:19

496

با صحبت امروز پزشکیان
من روی دلار ۱۱۰,۰۰۰ تومان دارم می‌بندم.

آخر سال تمام قراردادهای همکاری داخلیم تموم می‌شه و دستمزد جدید رو بر این اساس می‌گیرم، البته که دارم فرض می‌کنم دلار تا چندروز آینده به ۱۰۰,۰۰۰ تومان برسه و مدتی همین حوالی باشه‌.

اگر دلار واقعاً به ۱۱۰,۰۰۰ تومان برسه (که اصلاً بعید نیست)
قراردادهای سال بعدی رو روی دلار ۱۳۰,۰۰۰ تومان می‌بندم.

به ۲ دلیل این رو میگم:

۱- بچه‌های سنیور گفتند چطوری دستمزد بدیم برای سال بعد.

۲- چند نفر دعوت به همکاری کردن، گفتم حدود دستمزد رو بدوند که وقت هم رو نگیریم.

دستمزد فعلی رو بر اساس دلار ۶۰,۰۰۰ تومان بسته بودم سال قبل که خدا بیامرزش.
Rust for Python developers

05 Feb, 22:25

1,356

#5min_Rust

بعد از نصب rust برای ایجاد اولین پروژه از cargo استفاده می‌کنیم. با دستور cargo new pyrust شما یک پوشه جدید توی مسیری که این دستور رو اجرا کردید خواهید داشت به اسم pyrust.

تمام پروژه‌هایی که با cargo ایجاد می‌شوند حتما اسکلت مشابه دارند (مثال زیر)
.
├── Cargo.toml
├── .git
├── .gitignore
└── src
└── main.rs


قبل از بررسی فایل‌ها باید بگم که؛ این یک پروژه باینری هست (درآینده بررسی خواهیم کرد ولی اگر کتابخونه بود بجای main.rs شما lib.rs می‌دیدید)

تمام پروژه‌هایی که با cargo ایجاد می‌شوند بصورت خودکار git, gitignore رو خواهند داشت بریم باقی رو بررسی کنیم.

1) Cargo.toml
[package]
name = "pyrust"
version = "0.1.0"
edition = "2021"

[dependencies]

این فایل شامل اطلاعات پروژه هست؛ بخش dependencies بخشی هست که موقع استفاده از لایبراری‌های دیگه (ازین به بعد بهشون میگیم crate چون اسمش توی Rust این هست) باید پر کنید تا cargo اونهارو دانلود و استفاده کنه.

یک نکته دیگه که کمتر دقت میشه بهش؛ edition هست با این معنی که این پکیج باینری تا نسخه‌ای که سال 2021 منتشر شد backward compatibility رو داره.

شما ۳ تا ادیشن رو ممکنه ببینید :
۲۰۱۵ نسخه‌ای که Rust منتشر شد.
۲۰۱۸ نسخه‌ای که module, async/await و ... منتشر شد.
۲۰۲۰ نسخه‌ای که استانداردهای خیلی خوبی برای closure, iterate, ... منتشر شده.

همه چیز در Rust از src/main.rs و تابعی به اسم main شروع می‌شه؛ پس اگر پکیج باینتری داشته باشید حتما باید این موارد رو هم داشته باشید :

2) main.rs
fn main() {
println!("Hello, world!");
}


بصورت پیشفرض داخلی این فایل hello world رو خواهید داشت؛ fn کلمه کلیدی برای تعریف تابع هست main اسم تابع که هیچ آرگومانی بعنوان ورودی نمیگیره و هیچ چیزی هم بر نمی‌گردونه یا اصطلاحا unit type برمیگرده به () میگیم unit type و وقتی یک تابعی () بر میگردونه دیگه نیازی نیست اون رو بنویسیم اما اگر توی کد بالا می‌خواستیم بگیم که تابع main فقط unit type برمی‌گردونه کد به اینصورت م+یشد :
fn main() -> () {...}

از {} ها برای نمایش اسکوپ تابع (از کجا تا کجای کد مال این تابع هست) استفاده میشه همونطوری که توی پایتون برای اینکار از indentation استفاده می‌شه.
داخل این تابع فقط قرار هست یک متنی رو توی ترمینال چاپ کنیم؛ برای چاپ متن داخل ترمینال از println استفاده میشه که بعد از چاپ متن میره خط بعدی اگر نخواستیم بره خط بعدی از print استفاده می‌کنیم.
println!(), print!()

اما اگر دقت کنید توی کد بالا هم print و هم println هردو کنار اسمشون ! اومده؛ این ! اشتباه نیست و توی Rust یک مفهومی رو معرفی می‌کنه به اسم Macro پس نه print و نه println هیچکدوم تابع نیستند.

خیلی خلاصه بخوام بگم؛ وقتی کامپایلر یک macro توی کد شما می‌بینه می‌دونه که باید اون بخش از کدشما رو برداره و بر اساس یک الگوی خاص کد دیگری رو با پارامتر ورودی شما جایگزینش کنه.
در آخر هم توجه شمارو به ; جلب می‌کنم.

قبل از اجرای کد؛ اگر از rust-analyzer استفاده می‌کنید حتما باید داخل پوشه‌ای باشید که Cargo.toml قرار داره.

❯ cargo run
Compiling pyrust v0.1.0 (/home/mo.abbasi/Desktop/codes/learning/rust/pyrust)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.64s
Running `target/debug/pyrust`
Hello, world!

رو می‌تونید برای اجرای پروژه استفاده کنید؛ اگر از cargo run برای اجرا استفاده کنید نسخه‌ای که کامپایل میشه نسخه development هست و برای اینکه سریعتر کامپایل انجام بشه unomptimized هست (که توی توضیحات هم چاپ میشه) اگر توی نسخه develop نخواستید این توضیحات رو ببینید از دستور cargo run -q استفاده کنید.

بعد از اولین اجرا یا به محض فعال شدن rust analyzer؛ ۱ فایل و ۱ پوشه جدید توی پروژه خواهید دید. Cargo.lock که هیچوقت بهش دست نمیزنیم و جزئیات dependency هارو نگه میداره و البته پوشه target که نسخه کامپایل رو نگه می‌داره چون پروژه رو تو حالت development/debug کامپایل کردیم الان می‌تونیم فایل باینتری - کامپایل شده رو از پوشه target هم ببینید و اجرا کنیم :
target/debug/pyrust


تبریک می‌گم شما با ساختار اصلی و اولیه پروژه باینری در Rust آشنا شدید.