سلام، کارگو!

کارگو سیستم بیلد و مدیر بسته‌های Rust است. بیشتر برنامه‌نویسان Rust از این ابزار برای مدیریت پروژه‌هایشان استفاده می‌کنند، چون کارگو وظایف زیادی را به‌صورت خودکار انجام می‌دهد، مثل بیلد کردن کد، دانلود کتابخانه‌های موردنیاز، و بیلد کردن آن کتابخانه‌ها. (به این کتابخانه‌های موردنیاز وابستگی می‌گوییم.)

برنامه‌های ساده‌ی Rust، مثل همانی که تا الآن نوشتیم، معمولاً هیچ وابستگی‌ای ندارند. اگر پروژه‌ی "Hello, world!" را با کارگو بیلد می‌کردیم، فقط از بخش بیلد آن استفاده می‌شد. اما هرچه برنامه‌ات پیچیده‌تر شود، احتمالاً به وابستگی‌هایی نیاز خواهی داشت، و اگر پروژه‌ات را از اول با کارگو شروع کنی، اضافه کردن این وابستگی‌ها خیلی راحت‌تر می‌شود.

چون بیشتر پروژه‌های Rust از کارگو استفاده می‌کنند، این کتاب هم فرض می‌کند که تو هم از آن استفاده می‌کنی. اگر Rust را با نصب‌کننده‌ی رسمی آن نصب کرده باشی، کارگو هم همراهش نصب شده است. اما اگر به روش دیگری نصب کرده‌ای، می‌توانی با این دستور بررسی کنی که کارگو نصب است یا نه:

$ cargo --version

اگر یک شماره نسخه دیدی، یعنی نصب شده! ولی اگر خطایی مثل command not found دیدی، باید مستندات روش نصب را بررسی کنی تا ببینی چطور کارگو را جداگانه نصب کنی.

ساخت یک پروژه با کارگو

حالا بیایید یک پروژه‌ی جدید با کارگو بسازیم و تفاوت‌هایش با پروژه‌ی اولیه‌ی "Hello, world!" را ببینیم. ابتدا به پوشه‌ی پروژه‌هایت برگرد (یا هر جایی که کدهایت را ذخیره می‌کنی) و این دستورات را اجرا کن:

$ cargo new hello_cargo
$ cd hello_cargo

دستور اول یک پوشه‌ی جدید به نام hello_cargo می‌سازد و فایل‌های پروژه را داخل آن قرار می‌دهد. بعد از ورود به این پوشه، اگر لیست فایل‌های داخل آن را ببینی، کارگو دو فایل و یک پوشه برایت ساخته است:

  • فایل Cargo.toml
  • یک پوشه به نام src که فایل main.rs داخل آن قرار دارد.

همچنین کارگو یک ریپازیتوری Git و فایل .gitignore را هم ایجاد کرده است. البته اگر دستور cargo new را داخل یک ریپازیتوری Git اجرا کنی، این فایل‌ها ساخته نمی‌شوند. اگر بخواهی این رفتار را تغییر بدهی، می‌توانی از cargo new --vcs=git استفاده کنی.

نکته: Git یک سیستم کنترل نسخه‌ی معروف است. می‌توانی مشخص کنی که cargo new از چه سیستم کنترلی استفاده کند یا اینکه اصلاً از هیچ سیستمی استفاده نکند. برای دیدن گزینه‌های مختلف، cargo new --help را اجرا کن.

حالا Cargo.toml را در ویرایشگر موردعلاقه‌ات باز کن. محتوای آن باید شبیه این باشد:

[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2021"

# برای اطلاعات بیشتر به این لینک مراجعه کن:
# https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

این فایل با فرمت [TOML] نوشته شده است که یک فرمت ساده و خوانا برای پیکربندی کارگو است.

بخش [package] اطلاعاتی مثل نام پروژه، نسخه و ویرایش Rust را مشخص می‌کند. بخش [dependencies] جایی است که می‌توانی وابستگی‌های پروژه‌ات را تعریف کنی. در این پروژه به هیچ بسته‌ی اضافی نیاز نداریم، اما در فصل دوم از آن استفاده خواهیم کرد.

حالا src/main.rs را باز کن:

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

همان برنامه‌ی ساده‌ی "Hello, world!" است که قبلاً نوشتیم! تنها تفاوت این است که کارگو فایل را داخل پوشه‌ی src قرار داده و فایل Cargo.toml را در پوشه‌ی اصلی پروژه ساخته است.

کارگو انتظار دارد که همه‌ی کدهای پروژه داخل پوشه‌ی src باشند، و پوشه‌ی اصلی فقط شامل فایل‌هایی مثل README، مجوز، و تنظیمات باشد. این ساختار باعث نظم بیشتر پروژه‌ها می‌شود.

اگر پروژه‌ای را بدون کارگو شروع کرده‌ای (مثل همین "Hello, world!")، می‌توانی آن را به پروژه‌ای که از کارگو استفاده می‌کند تبدیل کنی. فقط کافی است کدهای پروژه را داخل پوشه‌ی src بگذاری و یک فایل Cargo.toml ایجاد کنی. یک راه آسان برای ساخت این فایل، اجرای دستور cargo init است که به‌صورت خودکار آن را برایت می‌سازد.

بیلد و اجرای پروژه با کارگو

حالا ببینیم اجرای برنامه‌ی "Hello, world!" با کارگو چه تفاوتی دارد. داخل پوشه‌ی hello_cargo، دستور زیر را اجرا کن:

$ cargo build
   Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs

این دستور یک فایل اجرایی در مسیر target/debug/hello_cargo (یا در ویندوز target\debug\hello_cargo.exe) ایجاد می‌کند، نه در دایرکتوری فعلی شما. چون ساخت پیش‌فرض در حالت دیباگ (debug) است، Cargo فایل باینری را در یک دایرکتوری به نام debug قرار می‌دهد. برای اجرای این فایل اجرایی، می‌توانید این دستور را بزنید:

$ ./target/debug/hello_cargo  # در ویندوز: .\target\debug\hello_cargo.exe

اگر همه چیز درست باشد، Hello, world! در ترمینال نمایش داده می‌شود. اجرای cargo build برای اولین بار یک فایل جدید به نام Cargo.lock در سطح بالای پروژه ایجاد می‌کند. این فایل نسخه‌ی دقیق وابستگی‌های پروژه را ثبت می‌کند. این پروژه وابستگی‌ای ندارد، پس فایل تقریباً خالی خواهد بود. نیازی به ویرایش دستی این فایل ندارید، چون Cargo خودش آن را مدیریت می‌کند.

ما پروژه را با cargo build ساختیم و با ./target/debug/hello_cargo اجرا کردیم، اما می‌توانیم از cargo run استفاده کنیم تا همزمان هم کد را کامپایل کند و هم آن را اجرا کند:

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/hello_cargo`
Hello, world!

استفاده از cargo run راحت‌تر از این است که هر بار cargo build را اجرا کنیم و بعد مسیر کامل باینری را وارد کنیم، به همین دلیل بیشتر توسعه‌دهندگان از cargo run استفاده می‌کنند.

اگر در کد تغییری نداده باشید، Cargo متوجه می‌شود و دوباره پروژه را نمی‌سازد، فقط باینری را اجرا می‌کند. اما اگر تغییری در کد داده باشید، Cargo قبل از اجرا پروژه را دوباره می‌سازد و چنین خروجی‌ای خواهید دید:

$ cargo run
   Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs
     Running `target/debug/hello_cargo`
Hello, world!

Cargo یک دستور دیگر هم دارد به نام cargo check که به جای تولید فایل اجرایی، فقط بررسی می‌کند که آیا کد شما کامپایل می‌شود یا نه:

$ cargo check
 Checking hello_cargo v0.1.0 (file:///projects/hello_cargo)
 Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs

چرا باید بخواهید که یک فایل اجرایی ساخته نشود؟ چون cargo check معمولاً خیلی سریع‌تر از cargo build اجرا می‌شود، چون مرحله‌ی تولید فایل اجرایی را رد می‌کند. اگر مدام در حال بررسی کد هنگام نوشتن هستید، استفاده از cargo check سرعت کار را بالا می‌برد. به همین دلیل، بیشتر برنامه‌نویسان Rust هنگام کدنویسی از cargo check استفاده می‌کنند و وقتی آماده‌ی اجرای برنامه شدند، از cargo build استفاده می‌کنند.

خلاصه‌ی کارهایی که تا الآن یاد گرفتیم:

  • با cargo new می‌توانیم یک پروژه جدید بسازیم.
  • با cargo build می‌توانیم پروژه را کامپایل کنیم.
  • با cargo run همزمان پروژه را کامپایل و اجرا کنیم.
  • با cargo check بدون ساختن باینری، بررسی کنیم که کد مشکلی ندارد.
  • Cargo خروجی بیلد را به جای قرار دادن در دایرکتوری پروژه، داخل target/debug ذخیره می‌کند.

یکی از مزیت‌های Cargo این است که دستوراتش در همه‌ی سیستم‌عامل‌ها یکسان هستند، پس دیگر نیازی نیست برای لینوکس، مک و ویندوز دستور جداگانه بنویسیم.

بیلد نسخه‌ی Release

وقتی پروژه‌ آماده‌ی انتشار شد، می‌توانید با cargo build --release آن را با بهینه‌سازی کامپایل کنید. این دستور یک فایل اجرایی در مسیر target/release ایجاد می‌کند، نه target/debug. بهینه‌سازی‌ها باعث می‌شوند که کد سریع‌تر اجرا شود، اما زمان کامپایل را افزایش می‌دهند. به همین دلیل، دو حالت مختلف برای بیلد وجود دارد: یکی برای توسعه که سریع‌تر ساخته شود، و یکی برای انتشار که سرعت اجرا بالاتر باشد.

اگر می‌خواهید عملکرد برنامه را تست کنید، حتماً با cargo build --release کامپایل کنید و فایل اجرایی داخل target/release را اجرا کنید.

Cargo و استانداردهای آن

در پروژه‌های ساده، Cargo تفاوت زیادی با استفاده‌ی مستقیم از rustc ندارد، اما وقتی پروژه‌ها پیچیده‌تر می‌شوند یا وابستگی‌های بیشتری دارند، مدیریت کارها با Cargo بسیار راحت‌تر خواهد شد.

حتی در همین پروژه‌ی ساده‌ی hello_cargo، ما از ابزارهایی استفاده کردیم که در کل مسیر یادگیری Rust به کار خواهند آمد. اگر روی یک پروژه‌ی موجود کار می‌کنید، کافی است کد را از گیت دریافت کنید، وارد دایرکتوری پروژه شوید و آن را بسازید (بیلد کنید):

$ git clone example.org/someproject
$ cd someproject
$ cargo build

برای اطلاعات بیشتر درباره‌ی Cargo، می‌توانید مستندات آن را مطالعه کنید.

جمع‌بندی

شما شروع بسیار خوبی در یادگیری Rust داشتید! در این فصل یاد گرفتید که:

  • نسخه‌ی پایدار Rust را با rustup نصب کنید.
  • نسخه‌ی Rust را به‌روز کنید.
  • مستندات محلی نصب‌شده را باز کنید.
  • یک برنامه‌ی ساده‌ی Hello, world! را با rustc بنویسید و اجرا کنید.
  • یک پروژه‌ی جدید بسازید و اجرا کنید، مطابق استانداردهای Cargo.

حالا زمان مناسبی است که یک برنامه‌ی کاربردی‌تر بنویسید تا بیشتر با Rust آشنا شوید. در فصل بعد، یک بازی حدس اعداد خواهیم ساخت. اما اگر ترجیح می‌دهید ابتدا با مفاهیم پایه‌ی برنامه‌نویسی در Rust آشنا شوید، می‌توانید فصل ۳ را مطالعه کنید و بعد به فصل ۲ برگردید.