نوشتن پیام‌های خطا به خروجی خطای استاندارد به جای خروجی استاندارد

در حال حاضر، ما تمام خروجی‌های خود را با استفاده از ماکروی println! به ترمینال می‌نویسیم. در بیشتر ترمینال‌ها، دو نوع خروجی وجود دارد: خروجی استاندارد (stdout) برای اطلاعات عمومی و خروجی خطای استاندارد (stderr) برای پیام‌های خطا. این تمایز به کاربران امکان می‌دهد که خروجی موفقیت‌آمیز یک برنامه را به یک فایل هدایت کنند اما همچنان پیام‌های خطا را روی صفحه ببینند.

ماکروی println! فقط قادر به نوشتن در خروجی استاندارد است، بنابراین برای نوشتن به خروجی خطای استاندارد باید از چیزی دیگر استفاده کنیم.

بررسی محل نوشتن خطاها

ابتدا بررسی می‌کنیم که محتوای چاپ‌شده توسط minigrep در حال حاضر به خروجی استاندارد نوشته می‌شود، از جمله پیام‌های خطایی که می‌خواهیم به جای آن‌ها در خروجی خطای استاندارد نوشته شوند. این کار را با هدایت جریان خروجی استاندارد به یک فایل و عمداً ایجاد یک خطا انجام خواهیم داد. ما جریان خروجی خطای استاندارد را هدایت نمی‌کنیم، بنابراین هر محتوایی که به خروجی خطای استاندارد ارسال شود همچنان روی صفحه نمایش داده خواهد شد.

برنامه‌های خط فرمان انتظار می‌رود که پیام‌های خطای خود را به جریان خروجی خطای استاندارد ارسال کنند تا در صورت هدایت جریان خروجی استاندارد به یک فایل، پیام‌های خطا همچنان روی صفحه نمایش داده شوند. برنامه ما در حال حاضر به درستی عمل نمی‌کند: ما به زودی خواهیم دید که پیام خطا به جای صفحه نمایش به فایل ذخیره می‌شود!

برای نشان دادن این رفتار، برنامه را با استفاده از دستور > و مسیر فایل output.txt که می‌خواهیم جریان خروجی استاندارد را به آن هدایت کنیم، اجرا می‌کنیم. هیچ آرگومانی ارائه نخواهیم کرد، که باید منجر به یک خطا شود:

$ cargo run > output.txt

دستور > به شل می‌گوید که محتوای جریان خروجی استاندارد را به output.txt بنویسد به جای اینکه آن را روی صفحه نمایش دهد. ما پیام خطایی که انتظار داشتیم روی صفحه ببینیم را ندیدیم، بنابراین به این معنی است که باید در فایل ذخیره شده باشد. این همان چیزی است که output.txt شامل می‌شود:

Problem parsing arguments: not enough arguments

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

نوشتن خطاها به خروجی خطای استاندارد

ما از کدی که در لیستینگ 12-24 نشان داده شده است برای تغییر نحوه چاپ پیام‌های خطا استفاده می‌کنیم. به دلیل بازسازی‌ای که قبلاً در این فصل انجام دادیم، تمام کدی که پیام‌های خطا را چاپ می‌کند در یک تابع به نام main قرار دارد. کتابخانه استاندارد ماکروی eprintln! را ارائه می‌دهد که به جریان خروجی خطای استاندارد چاپ می‌کند، بنابراین دو جایی که ما println! را برای چاپ خطاها فراخوانی کرده‌ایم را به eprintln! تغییر می‌دهیم.

Filename: src/main.rs
use std::env;
use std::process;

use minigrep::Config;

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

    let config = Config::build(&args).unwrap_or_else(|err| {
        eprintln!("Problem parsing arguments: {err}");
        process::exit(1);
    });

    if let Err(e) = minigrep::run(config) {
        eprintln!("Application error: {e}");
        process::exit(1);
    }
}
Listing 12-24: نوشتن پیام‌های خطا به خروجی خطای استاندارد به جای خروجی استاندارد با استفاده از eprintln!

حالا برنامه را دوباره اجرا می‌کنیم به همان روش، بدون هیچ آرگومانی و با هدایت خروجی استاندارد با استفاده از >:

$ cargo run > output.txt
Problem parsing arguments: not enough arguments

حالا خطا را روی صفحه می‌بینیم و output.txt خالی است، که همان رفتاری است که از برنامه‌های خط فرمان انتظار داریم.

برنامه را دوباره اجرا می‌کنیم با آرگومان‌هایی که خطایی ایجاد نمی‌کنند اما همچنان خروجی استاندارد را به یک فایل هدایت می‌کنند، مانند این:

$ cargo run -- to poem.txt > output.txt

هیچ خروجی روی ترمینال نخواهیم دید و output.txt شامل نتایج ما خواهد بود:

Filename: output.txt

Are you nobody, too?
How dreary to be somebody!

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

خلاصه

این فصل به طور خلاصه برخی از مفاهیم اصلی که تاکنون آموخته‌اید را مرور کرد و توضیح داد که چگونه عملیات ورودی/خروجی معمول را در Rust انجام دهید. با استفاده از آرگومان‌های خط فرمان، فایل‌ها، متغیرهای محیطی و ماکروی eprintln! برای چاپ خطاها، شما اکنون آماده‌اید تا برنامه‌های خط فرمان بنویسید. همراه با مفاهیم فصل‌های قبلی، کد شما سازماندهی خوبی خواهد داشت، داده‌ها را به طور مؤثر در ساختارهای داده مناسب ذخیره می‌کند، خطاها را به خوبی مدیریت می‌کند و به خوبی تست شده است.