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 เพื่อให้เฉพาะข้อมูลจากการรันที่สำเร็จไปสิ้นสุดในไฟล์ เราจะเปลี่ยนนั้น
Print Error ไปยัง Standard Error
เราจะใช้โค้ดใน Listing 12-24 เพื่อเปลี่ยนวิธีที่ข้อความ error ถูก
print เพราะ refactor ที่เราทำไปแล้วในบทนี้ โค้ดทั้งหมดที่ print
ข้อความ error อยู่ในฟังก์ชันเดียว main standard library ให้มาโคร
eprintln! ที่ print ไปยัง standard error stream ดังนั้นมาเปลี่ยน
สองที่ที่เรากำลังเรียก println! เพื่อ print error ให้ใช้
eprintln! แทน
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(())
}
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