一、标准输入和输出
在谈文件读写时提到,它也算是IO的一种,这次谈一下标准的输入输出。什么是标准的输入输出?其实简单理解一下就是IO读写操作到stdin 和stdout上的输入和输出,其实还有类似的stderr等。这些可能是屏幕也可能是其它显示单元,甚至可能是一个“黑洞”。
二、Rust中的对其的支持
在Rust的std::io中也提供了相关的IO标准输入和输出,在其它一些语言中也有叫做输入输出流的,意思基本都是一个意思,只要不是过于严格的场景声明基本可以当成一回事。在Rust中,其实这些操作是实现了Trait来实现的,看一下相关的定义:
pub trait Read {
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> { ... }
fn is_read_vectored(&self) -> bool { ... }
unsafe fn initializer(&self) -> Initializer { ... }
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> { ... }
fn read_to_string(&mut self, buf: &mut String) -> Result<usize> { ... }
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> { ... }
fn by_ref(&mut self) -> &mut Self
where
Self: Sized,
{ ... }
fn bytes(self) -> Bytes<Self>ⓘ
where
Self: Sized,
{ ... }
fn chain<R: Read>(self, next: R) -> Chain<Self, R>ⓘ
where
Self: Sized,
{ ... }
fn take(self, limit: u64) -> Take<Self>ⓘ
where
Self: Sized,
{ ... }
}
pub trait BufRead: Read {
fn fill_buf(&mut self) -> Result<&[u8]>;
fn consume(&mut self, amt: usize);
fn has_data_left(&mut self) -> Result<bool> { ... }
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> { ... }
fn read_line(&mut self, buf: &mut String) -> Result<usize> { ... }
fn split(self, byte: u8) -> Split<Self>ⓘ
where
Self: Sized,
{ ... }
fn lines(self) -> Lines<Self>ⓘ
where
Self: Sized,
{ ... }
}
看一下调用标准转入的例子:
use std::io::{self, BufRead};
fn main() -> io::Result<()> {
let mut buffer = String::new();
let stdin = io::stdin();
let mut handle = stdin.lock();
handle.read_line(&mut buffer)?;
Ok(())
}
再看一下写操作:
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize>;
fn flush(&mut self) -> Result<()>;
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> { ... }
fn is_write_vectored(&self) -> bool { ... }
fn write_all(&mut self, buf: &[u8]) -> Result<()> { ... }
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<()> { ... }
fn write_fmt(&mut self, fmt: Arguments<'_>) -> Result<()> { ... }
fn by_ref(&mut self) -> &mut Self
where
Self: Sized,
{ ... }
}
相关的例子:
//隐式同步
use std::io::{self, Write};
fn main() -> io::Result<()> {
io::stdout().write_all(b"hello world")?;
Ok(())
}
//显示同步
use std::io::{self, Write};
fn main() -> io::Result<()> {
let stdout = io::stdout();
let mut handle = stdout.lock();
handle.write_all(b"hello world")?;
Ok(())
}
再看一个综合的例子:
fn main() {
let mut input = String::new();
std::io::stdin()
.read_line(&mut input)
.expect("Failed to read line");
// 这里等效的写法是:
// let num: i32 = input.trim().parse().unwrap();
let num = input.trim().parse::<i32>().unwrap();
println!("您输入的数字是:{}", num);
}
这段代码是从标准输入中拿数字类型的字符。另外,在实际应用中,有一个print!这个宏,用来做行缓冲机制的,这个就不举例子了,用得太多了。
三、总结
输入输出这个东西其实就是一脉相承,所有的语言可以造别的新东西,这个得继承,因为所有的硬件和OS基本都沿袭这么做。想要有所改变,可以改别的,这个短期内是看改不动的。支持的好或不好,就很容易看出来应用的方便性,至少在屏幕上打个日志不能够搞得老复杂吧。
努力吧,归来的少年!