Q: Am I approaching writing idiomatic Rust code correctly?
Hi CodeReview, I'm a beginner Rustacean coming from Python going through Rust books (The Rust Book, Rust in Action). A lot of the beginner code has unwrap everywhere and I'd like to write more idiomatic Rust.
I wrote 2 versions of a simple CLI program that reads a file and prints it to stdout, one with .unwrap
and one without.
Both version execute successfully and do the same thing, only differing in the error-handling.
I tried to expand out all cases of .unwrap
based on things in the official docs about using .unwrap
[1][2][3].
Protoyping
extern crate clap;
use std::{
prelude,
io::{BufRead, BufReader},
fs::File,
};
use clap::{App, Arg};
fn main() {
let matches = App::new("File reader")
.about("Read a file line by line")
.help("The help text")
.version("0.1")
.arg(Arg::with_name("input")
.value_name("INPUT")
.takes_value(true)
.help("Any text file to be read"))
.get_matches();
// Get input argument, ensure it is valid
let input = matches.value_of("input").unwrap();
// Try and open the file
let f = File::open(input).unwrap();
// Load the file into BufReader
let reader = BufReader::new(f);
// Read the lines of the file
for line_ in reader.lines() {
let line = line_.unwrap();
println!("{}", line);
}
}
Improving robustness
use std::{
error::Error,
// prelude::*,
io::{BufRead, BufReader},
fs::File,
};
use clap::{App, Arg};
fn main() -> Result<(), Box<dyn Error>> {
let matches = App::new("File reader")
.about("Read a file line by line")
.help("The help text")
.version("0.1")
.arg(Arg::with_name("input")
.value_name("INPUT")
.takes_value(true)
.help("Any text file to be read"))
.get_matches();
// Get input argument, ensure it is valid
let input = matches.value_of("input");
let input = match input {
Some(file) => file,
None => matches.usage(),
};
// Try and open the file
let f = File::open(input)?;
// Load the file into BufReader
let reader = BufReader::new(f);
// Read the lines of the file
// "if let" reads "if 'let' destructures line_ into Ok(line) value, evaluate {}"
for line_ in reader.lines() {
if let Ok(line) = line_ {
println!("{}", line);
};
}
Ok(())
}
Am I approaching making my code more idiomatic correctly?
Edit 2: My second take at making it more readable/idiomatic (fn main
only)
fn main() -> Result<(), Box<dyn Error>> {
let matches = App::new("File reader")
.about("Read a file line by line")
.help("The help text")
.version("0.1")
.arg(Arg::with_name("input")
.value_name("INPUT")
.takes_value(true)
.help("Any text file to be read"))
.get_matches();
// Get input argument, ensure it is valid
let input = match matches.value_of("input") {
Some(input) => input,
None => matches.usage(),
};
// Try and open the file
if let Ok(f) = File::open(input){
// If valid, load into BufReader then read the file line by line
let reader = BufReader::new(f);
for line_ in reader.lines() {
if let Ok(line) = line_ {
println!("{}", line);
};
};
} else {
// If file is not valid, print the CLI usage
println!("{}", matches.usage())
};
Ok(())
}