31
loading...
This website collects cookies to deliver better user experience
Read
and Write
traits, we can swap the input and output for byte arrays and vectors during testing instead.grep(1)
filters lines read from stdin with a search pattern ("three" in this case) and prints the matching lines to stdout. After starting, grep
halts to wait for input from stdin. By typing this input into the terminal, we can see that grep
prints any line that matches the pattern back to stdout, which the terminal displays. Then, the program returns to waiting for input until it receives an EOF (end-of-file), which we pass by pressing kbd:[ctrl]+kbd:[D] in the terminal.$ grep three
one
two
three
three
ls(1)
prints the current directory's contents to stdout. This example uses a pipe (|
) to create a pipeline, to pass the output from ls
as input to grep
. grep
then filters to only print lines matching the passed pattern ("Cargo").$ ls -l ~/pager | grep Cargo
Cargo.lock
Cargo.toml
Stdin
, Stdout
and Stderr
structs, which are created with the io::stdin()
, io::stdout()
and io::stderr()
functions respectively.src/main.rs
use std::io;
use std::io::{Read, Write};
fn main() -> io::Result<()> {
let mut buffer = "".to_string();
io::stdin().read_to_string(&mut buffer)?;
io::stdout().write_all(buffer.to_uppercase().as_bytes())?;
Ok(())
}
Stdin
and Stdout
structs and pass the input and output as arguments to a more abstract, separate function.Stdin
and Stdout
out for other implementors of the Read
and Write
traits: a byte array for input and a vector for output.src/lib.rs
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn writes_upcased_input_to_output() {
let mut output: Vec<u8> = Vec::new();
upcase(&mut "Hello, world!\n".as_bytes(), &mut output).unwrap();
assert_eq!(&output, b"HELLO, WORLD!\n");
}
}
Read
and Write
traits:src/lib.rs
pub fn upcase(
input: &mut impl Read,
output: &mut impl Write,
) -> Result<(), Error> {
let mut buffer = "".to_string();
input.read_to_string(&mut buffer)?;
output.write_all(buffer.to_uppercase().as_bytes())?;
Ok(())
}
src/main.rs
with a call to our new implementation with a Stdin
and Stdout
struct for the input and output:src/main.rs
use std::io;
fn main() -> io::Result<()> {
upcase::upcase(&mut io::stdin(), &mut io::stdout())
}
Stdin
and Stdout
out of the implementation, we made our program more modular, allowing us to test the code without resorting to capturing stdout to assert that the printed result matched our expectations.File
to upcase()
.File
also implements the Read
trait, that would work without further modifications in our implementation.Another issue with this example is that it uses Read::read_to_string()
, which will read the contents of the whole stream from the input before writing everything to stdout at once, which is inefficient, especially for larger inputs. A more efficient implementation could use buffered reading through the BufRead
trait to read and write the input stream line by line. ↩