Rust - Input Output
Rust - Basic Input & Output
Section titled “Rust - Basic Input & Output”This chapter covers the fundamentals of interacting with a user: reading from standard input (the keyboard) and writing to standard output (the console). We’ll also look at how to process command-line arguments.
The Read and Write Traits
Section titled “The Read and Write Traits”Rust’s standard I/O library (std::io) is built around two fundamental traits: Read for input and Write for output.
Read: For sources you can read bytes from, likestd::io::stdin()or aFile.Write: For destinations you can write bytes to, likestd::io::stdout()or aFile.
Reading from the Console
Section titled “Reading from the Console”To read a line of text from the user, you can use the read_line method on the handle for standard input. This operation might fail (e.g., due to an OS-level error), so it returns a Result type, which you must handle.
use std::io;
fn main() { println!("Please enter your name:");
let mut name = String::new();
// Get a handle to standard input and read a line. // read_line returns a Result, so we use .expect() for simple error handling. io::stdin() .read_line(&mut name) .expect("Failed to read line");
// The `read_line` includes the newline character, so we can trim it. println!("Hello, {}. Nice to meet you!", name.trim());}Understanding .expect()
Section titled “Understanding .expect()”The .expect("message") call is a shortcut. If the Result is Ok, it returns the value inside. If it’s Err, it will cause the program to panic (crash) and display the message you provided. It’s useful for examples and prototypes, but in production code, you should often use a match statement or other methods for more graceful error handling.
Writing to the Console
Section titled “Writing to the Console”You’ve already seen the easiest way to write to the console: the println! and print! macros. They are convenient and handle formatting for you.
fn main() { let name = "Alice"; let age = 30; println!("Name: {}, Age: {}", name, age); // Prints with a newline print!("This will be on the "); // Prints without a newline print!("same line.\n");}Under the hood, these macros use the std::io::stdout() handle. You can use this handle directly with the Write trait if you need more control, but println! is usually sufficient.
Handling Command-Line Arguments
Section titled “Handling Command-Line Arguments”Programs are often launched with arguments from the command line. Rust’s standard library provides a simple way to access these arguments via std::env::args().
Basic Usage
Section titled “Basic Usage”std::env::args() returns an iterator that yields the arguments as strings. The first argument (args[0]) is always the path to your program’s executable.
// Save as main.rs and run with: `cargo run -- arg1 arg2`use std::env;
fn main() { let args: Vec<String> = env::args().collect(); println!("All arguments: {:?}", args);
// The first argument is the program path let program_path = &args[0]; println!("Program path: {}", program_path);
// Access the other arguments if args.len() > 1 { let first_arg = &args[1]; println!("First argument: {}", first_arg); }}A More Practical Example: Summing Numbers
Section titled “A More Practical Example: Summing Numbers”Let’s create a program that sums numbers passed as command-line arguments. This involves skipping the first argument and parsing the rest from strings into numbers. This is a great example of where iterators shine.
// Run with: `cargo run -- 10 20 5`use std::env;
fn main() { let mut total = 0;
// env::args() gives an iterator. .skip(1) creates a new iterator that // skips the first element (the program path). for arg in env::args().skip(1) { // .parse() returns a Result, which we handle with a match. match arg.parse::<i32>() { Ok(num) => { total += num; } Err(_) => { eprintln!("Error: '{}' is not a valid integer. Skipping.", arg); } } }
println!("Total sum: {}", total);}This example is much more robust. It uses .skip(1) for idiomatic iteration and a match to gracefully handle arguments that aren’t valid numbers, printing an error to standard error (eprintln!) instead of crashing.
Pro-Tip: Using a Crate for Complex Arguments
Section titled “Pro-Tip: Using a Crate for Complex Arguments”For any real-world application, parsing command-line arguments manually can become tedious. The Rust ecosystem has excellent libraries (called ‘crates’) for this. A very popular one is clap. It allows you to declaratively define your application’s CLI interface, and it handles parsing, validation, and generating help messages for you automatically.
While std::env::args() is great for simple cases, consider using a crate like clap once your needs grow beyond a few positional arguments.