مقدمه

به فصل «ساخت یک برنامه CLI» خوش آمدید. در این فصل، با ساخت یک پروژه عملی، بسیاری از مفاهیمی را که تاکنون یاد گرفته‌ایم، به کار خواهیم بست. پروژه ما ساخت یک نسخه ساده‌شده از ابزار خط فرمان کلاسیک grep (globally search a regular expression and print) خواهد بود. این ابزار یک رشته و یک مسیر فایل را به عنوان آرگومان دریافت کرده و در آن فایل به دنبال خطوطی می‌گردد که حاوی آن رشته هستند.

اولین قدم در ساخت هر ابزار خط فرمانی، توانایی خواندن آرگومان‌هایی است که کاربر در کامند لاین به برنامه پاس می‌دهد.

خواندن آرگومان‌ها با std::env::args

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

تکرارگر آرگومان‌ها

تابع std::env::args() یک «تکرارگر» (iterator) از آرگومان‌های خط فرمان را برمی‌گرداند. تکرارگرها نوعی هستند که یک دنباله از مقادیر را تولید می‌کنند و می‌توان روی آنها حلقه زد. یک روش رایج و ساده برای کار با تمام آرگومان‌ها به صورت یکجا، استفاده از متد .collect() روی این تکرارگر است تا آنها را در یک کالکشن، مانند یک وکتور (Vec<String>)، جمع‌آوری کنیم.

Copy Icon src/main.rs
use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();
    println!("Arguments: {:?}", args);
}

حالا بیایید این برنامه را با آرگومان‌های مختلف اجرا کنیم. به یاد داشته باشید که برای پاس دادن آرگومان به برنامه خود از طریق Cargo، باید بعد از cargo run از -- استفاده کرده و سپس آرگومان‌ها را وارد کنید.

$ cargo run -- arg1 arg2
Arguments: ["target/debug/minigrep", "arg1", "arg2"]
                    

همانطور که می‌بینید، اولین مقدار در وکتور (args[0])، همیشه نام و مسیر فایل اجرایی برنامه ماست. آرگومان‌های واقعی که ما به برنامه داده‌ایم، از ایندکس ۱ شروع می‌شوند.

دسترسی به مقادیر آرگومان‌ها

اکنون که آرگومان‌ها را در یک وکتور داریم، می‌توانیم با استفاده از ایندکس‌گذاری به آنها دسترسی پیدا کنیم. برای ابزار grep ما، به دو آرگومان نیاز داریم: یکی رشته مورد جستجو (query) و دیگری مسیر فایل (file path).

Copy Icon src/main.rs
use std::env;

fn main() {
    let args: Vec<String> = env::args().collect();

    // The first argument we care about is at index 1
    let query = &args[1];
    // The second one is at index 2
    let file_path = &args[2];

    println!("Searching for '{}'", query);
    println!("In file '{}'", file_path);
}

اجرای این کد با cargo run -- test poem.txt خروجی زیر را تولید خواهد کرد:

Searching for 'test'
In file 'poem.txt'
                    

این کد در حال حاضر بسیار شکننده است. اگر کاربر تعداد آرگومان‌های کمتری را وارد کند، دسترسی به args[1] یا args[2] باعث panic شدن برنامه خواهد شد. در درس‌های بعدی این فصل، به مدیریت خطای قوی برای این موارد خواهیم پرداخت.

در این درس اولین قدم برای ساخت ابزار خط فرمان خود را برداشتیم و یاد گرفتیم که چگونه آرگومان‌های ورودی از کاربر را با استفاده از std::env::args بخوانیم و آنها را در یک وکتور جمع‌آوری کنیم. این مهارت، نقطه شروع برای هر برنامه CLI در Rust است. مرحله بعدی، کار با فایل‌هاست. در درس بعد، به سراغ «خواندن یک فایل» خواهیم رفت و یاد می‌گیریم که چگونه محتوای فایلی را که کاربر مسیر آن را مشخص کرده است، در برنامه خود بخوانیم.