The answer by @A.B. is correct, but it tries to conform to OP's original program structure. I want to have a more readable alternative for newcomers who stumble upon this question (just like I did).
use std::env; use std::fs; use std::io::{self, BufReader, BufRead}; fn main() { let input = env::args().nth(1); let reader: Box<dyn BufRead> = match input { None => Box::new(BufReader::new(io::stdin())), Some(filename) => Box::new(BufReader::new(fs::File::open(filename).unwrap())) }; for line in reader.lines() { println!("{:?}", line); } } See the discussion in reddit from which I borrowed the code.
Note the dyn keyword before boxed BufRead. This pattern is called a trait object.