Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Redirect Error ไปยัง Standard Error

ตอนนี้ เราเขียน output ทั้งหมดของเราไปยัง terminal โดยใช้มาโคร println! ใน terminal ส่วนใหญ่ มี output สองประเภท — standard output (stdout) สำหรับข้อมูลทั่วไป และ standard error (stderr) สำหรับ ข้อความ error ความแตกต่างนี้ทำให้ user เลือกที่จะ direct output ที่ สำเร็จของโปรแกรมไปยังไฟล์ในขณะที่ยัง print ข้อความ error ไปยังหน้าจอ ได้

มาโคร println! สามารถ print เฉพาะไปยัง standard output ดังนั้นเรา ต้องใช้อย่างอื่นเพื่อ print ไปยัง standard error

ตรวจสอบว่า Error เขียนไปที่ไหน

ก่อนอื่น มาสังเกตว่าเนื้อหาที่ minigrep print ปัจจุบันถูกเขียนไปยัง standard output อย่างไร รวมข้อความ error ใด ๆ ที่เราต้องการเขียนไปยัง standard error แทน เราจะทำเช่นนั้นโดย redirect standard output stream ไปยังไฟล์ในขณะที่จงใจทำให้เกิด error เราจะไม่ redirect standard error stream ดังนั้นเนื้อหาใดที่ส่งไปยัง standard error จะยังแสดงบนหน้าจอ ต่อไป

โปรแกรม command line คาดหวังที่จะส่งข้อความ error ไปยัง standard error stream เพื่อให้เรายังเห็นข้อความ error บนหน้าจอแม้ว่าเรา redirect standard output stream ไปยังไฟล์ โปรแกรมของเราตอนนี้ทำตัวไม่ดี — เรา กำลังจะเห็นว่ามันบันทึก output ข้อความ error ไปยังไฟล์แทน!

เพื่อสาธิตพฤติกรรมนี้ เราจะรันโปรแกรมด้วย > และ file path output.txt ที่เราต้องการ redirect standard output stream ไป เรา จะไม่ส่งอาร์กิวเมนต์ใด ซึ่งควรทำให้เกิด error:

$ cargo run > output.txt

syntax > บอก shell ให้เขียนเนื้อหาของ standard output ไปยัง output.txt แทนหน้าจอ เราไม่ได้เห็นข้อความ error ที่เราคาดหวัง print ไปยังหน้าจอ ดังนั้นมันต้องไปสิ้นสุดในไฟล์ นี่คือสิ่งที่ output.txt มี:

Problem parsing arguments: not enough arguments

ใช่ ข้อความ error ของเรากำลังถูก print ไปยัง standard output มีประโยชน์ มากกว่าสำหรับข้อความ error แบบนี้ที่จะถูก print ไปยัง standard error เพื่อให้เฉพาะข้อมูลจากการรันที่สำเร็จไปสิ้นสุดในไฟล์ เราจะเปลี่ยนนั้น

เราจะใช้โค้ดใน Listing 12-24 เพื่อเปลี่ยนวิธีที่ข้อความ error ถูก print เพราะ refactor ที่เราทำไปแล้วในบทนี้ โค้ดทั้งหมดที่ print ข้อความ error อยู่ในฟังก์ชันเดียว main standard library ให้มาโคร eprintln! ที่ print ไปยัง standard error stream ดังนั้นมาเปลี่ยน สองที่ที่เรากำลังเรียก println! เพื่อ print error ให้ใช้ eprintln! แทน

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

use minigrep::{search, search_case_insensitive};

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) = run(config) {
        eprintln!("Application error: {e}");
        process::exit(1);
    }
}

pub struct Config {
    pub query: String,
    pub file_path: String,
    pub ignore_case: bool,
}

impl Config {
    fn build(args: &[String]) -> Result<Config, &'static str> {
        if args.len() < 3 {
            return Err("not enough arguments");
        }

        let query = args[1].clone();
        let file_path = args[2].clone();

        let ignore_case = env::var("IGNORE_CASE").is_ok();

        Ok(Config {
            query,
            file_path,
            ignore_case,
        })
    }
}

fn run(config: Config) -> Result<(), Box<dyn Error>> {
    let contents = fs::read_to_string(config.file_path)?;

    let results = if config.ignore_case {
        search_case_insensitive(&config.query, &contents)
    } else {
        search(&config.query, &contents)
    };

    for line in results {
        println!("{line}");
    }

    Ok(())
}
Listing 12-24: เขียนข้อความ error ไปยัง standard error แทน standard output โดยใช้ eprintln!

ตอนนี้มารันโปรแกรมอีกครั้งในแบบเดิม โดยไม่มีอาร์กิวเมนต์และ redirect standard output ด้วย >:

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

ตอนนี้เราเห็น error บนหน้าจอและ output.txt ไม่มีอะไร ซึ่งเป็น พฤติกรรมที่เราคาดหวังของโปรแกรม command line

มารันโปรแกรมอีกครั้งด้วยอาร์กิวเมนต์ที่ไม่ทำให้เกิด error แต่ยัง redirect standard output ไปยังไฟล์ แบบนี้:

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

เราจะไม่เห็น output ใด ๆ ที่ terminal และ output.txt จะบรรจุผลของ เรา:

Filename: output.txt

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

นี่สาธิตว่าตอนนี้เราใช้ standard output สำหรับ output ที่สำเร็จและ standard error สำหรับ output error ตามที่เหมาะสม

สรุป

บทนี้ทบทวนแนวคิดหลักบางอย่างที่คุณได้เรียนมา และครอบคลุมวิธีทำ operation I/O ทั่วไปใน Rust โดยใช้อาร์กิวเมนต์ command line, ไฟล์, environment variable และมาโคร eprintln! สำหรับ print error คุณ พร้อมที่จะเขียน application command line ตอนนี้ ผสมกับแนวคิดในบทก่อน หน้า โค้ดของคุณจะถูกจัดระเบียบดี เก็บข้อมูลอย่างมีประสิทธิภาพในโครงสร้าง ข้อมูลที่เหมาะสม จัดการ error อย่างดี และถูกทดสอบดี

ถัดไป เราจะสำรวจฟีเจอร์ Rust บางอย่างที่ได้รับอิทธิพลจากภาษา functional — closure และ iterator