IO 操作
std 是 Rust 的標準庫,其中 std::io 提供了多種 IO 操作的工具。
stdin.lock().lines() 解釋
io::stdin()給你一個標準輸入的 handle (控制代碼)。.lock()取得對標準輸入的鎖定(防止重複的系統調用並避免跨線程的資源競爭)。.lines()(來自BufReadtrait) 返回一個輸入行的迭代器。每次迭代產生一個Result<String, io::Error>;String包含單行內容,不包括末尾的換行符。
在程式設計中,控制代碼(handle)是對資源的抽象參照,當一個應用程式要參照其他系統(如資料庫、作業系統)所管理的主記憶體塊或對象時,可以使用控制代碼。
簡單的使用範例
use std::io::{self, BufRead};
fn main() {
let stdin = io::stdin(); // 取得標準輸入,也就是 `Stdin`
let mut handle = stdin.lock(); // 取得 `StdinLock`
for line_result in handle.lines() {
match line_result {
Ok(line) => {
if line.trim() == "quit" {
break;
}
println!("You typed: {}", line);
}
Err(err) => {
eprintln!("Error reading line: {}", err);
break;
}
}
}
}
執行上述這段程式碼,每輸入一行後按下 Enter,它會讀取該行並執行對應的程式碼,直到你輸入 quit。
小細節
- 所有權:每個
Ok(String)都是新分配的字串,並由你擁有;它不包括末尾的\n。 - 錯誤:你必須處理
Err(io::Error);在許多範例中,人們在原型設計時使用?或unwrap()。 - 何時結束:當用戶輸入
quit會中斷循環。 - 性能:使用
.lock()配合BufRead進行逐行讀取,是很常用且高效的做法。
使用 .filter_map() 跳過空行
use std::io::{self, BufRead};
fn main() {
let stdin = io::stdin();
let mut non_empty = stdin
.lock()
.lines()
.filter_map(|res| res.ok())
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty());
// 第一個非空行作為整數
let n: usize = non_empty
.next()
.and_then(|s| s.parse().ok())
.unwrap_or(0);
println!("N = {}", n);
}
慣用的解析模式
use std::io::{self, BufRead};
fn read_n_numbers() -> io::Result<Vec<i64>> {
let stdin = io::stdin();
let mut lines = stdin.lock().lines();
// 讀取第一個非空行作為 N
let n: usize = loop {
match lines.next() {
Some(Ok(l)) if !l.trim().is_empty() => match l.trim().parse() {
Ok(v) => break v,
Err(_) => return Err(io::Error::new(io::ErrorKind::InvalidData, "bad N")),
},
Some(Ok(_)) => continue, // 跳過空行
Some(Err(e)) => return Err(e),
None => return Err(io::Error::from(io::ErrorKind::UnexpectedEof)),
}
};
// 正好讀取 N 行
let mut out = Vec::with_capacity(n);
for _ in 0..n {
let line = match lines.next() {
Some(Ok(l)) => l,
Some(Err(e)) => return Err(e),
None => return Err(io::Error::from(io::ErrorKind::UnexpectedEof)),
};
let v: i64 = line.trim().parse().map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "bad int"))?;
out.push(v);
}
Ok(out)
}
這與你的程式使用的模式相同:從 stdin.lock().lines() 創建一次迭代器,然後用 next() 從中提取行,並相應地處理 Ok/Err/None。