These are chat archives for rust-lang/rust

May 2017
Joonas Koivunen
May 30 2017 05:46
forgot to follow-up here, I made rust-lang/rust#42295 yesterday after asking about it on #rust @ mozilla irc
Vasily Kirichenko
May 30 2017 09:37

Hi, all! What's the idiomatic way to get, say, first and second command line arguments?
I'm doing this:

let args = std::env::args().collect::<Vec<_>>();
let root = Path::new(&args[1]);
let file_count: i16 = args[2].parse().unwrap();

but it does not look super tidy nor super safe. Any suggestions?

Denis Lisov
May 30 2017 09:41
@vasily-kirichenko I'd suggest using a library for command line arguments. Something like clap or docopt.
Vasily Kirichenko
May 30 2017 09:43
wow. clap looks promising. thanks!
Vasily Kirichenko
May 30 2017 10:24
yes, clap is good, but matches.value_of("an_argument").unwrap() is not compile time checked, so a typo in an arg name can cause panic.
clap_app macro could add functions like matches.an_argument().unwrap()
or Rust macros cannot do this?
Sergey Noskov
May 30 2017 10:48
I've tried a structopt crate for option parsing. Liked it.
Daniel Collin
May 30 2017 10:55
Clap has tons of features but it depends a bit on what you need. You may get away with something similer also
Oh.. clap was just mentioned. Ignore me :)
You don't need to unwrap() unless you want to. You can handle the error yourself and report it back to the user.
Denis Lisov
May 30 2017 11:00
@Albibek Thank you, looks like a nice wrapper I'll probably use the next time I start a project :-)
Vasily Kirichenko
May 30 2017 11:22
@Albibek thanks, structopt is type safe and cool :)
Aleksey Kladov
May 30 2017 15:36
@vasily-kirichenko do look at docopt though! Clap is great when you want to create a perfect and complex command line interface. docopt is absolutely the best for quick and short command-line applications, and it is also compile-time checked!
Joonas Koivunen
May 30 2017 17:11
got my first procedural macro implemented, luckily there are good examples (like deepclone): ... it might be helpful if you are dealing with types that contain Cow types.. also, if you know a better way to avoid this crate altogether I'd like to hear about it :)
Roland Tepp
May 30 2017 19:17
Hey, I am relatively new to Rust so I need some guidance writing my first small CLI app
So, I am using clap to parse command line arguments and my app accepts a list of input file names
I want to read all those files and filter them based on some condition (think of grep like tool).
If no input file names have been given I want to read input from stdin
Roland Tepp
May 30 2017 19:27
The kind of processing I want to do is similar regardless of the source, so coming from a language with less fussy type system, I thought that I could iterate, map and flat_map my way through filenames until I got an iterator of opened file instances or return a singleton iterator with std::io:stdin()if no filenames are provided.
That did not work out quite as nicely as I expected though...
The code that I have right now looks like this:
    let events = match m.values_of("FILES") {
        None => EventReader::new(std::io::stdin()),
        Some(files) =>
            .filter(|&p| p.exists() && p.is_file())
            .filter_map(|path| {
                File::open(path).map_err(|e| {
                    writeln!(std::io::stderr(), "Failed to open {}: {}", path.display(), e)
EventReader is coming from xml-rs crate here.
So, what I eventually want to get at is a stream/iterator of XML parser events read either from a list of files defined on a command line or stdin if no files have been given
But Rust keeps complaining to me that the types at the both ends of match don’t match (what a nice pun there...)
Roland Tepp
May 30 2017 19:32
error[E0308]: match arms have incompatible types
  --> src/
29 |     let events = match m.values_of("FILES") {
   |                  ^ expected struct `xml::EventReader`, found struct `std::iter::FlatMap`
   = note: expected type `xml::EventReader<std::io::Stdin>`
              found type `std::iter::FlatMap<std::iter::FilterMap<std::iter::Filter<std::iter::Map<clap::Values<'_>, fn(&str) -> &std::path::Path {std::path::Path::new::<str>}>, [closure@src/ 32:51]>, [closure@src/ 37:14]>, xml::EventReader<std::fs::File>, fn(std::fs::File) -> xml::EventReader<std::fs::File> {<xml::EventReader<R>><std::fs::File>::new}>`
note: match arm with an incompatible type
  --> src/
31 |           Some(files) =>
   |  ________________________^ starting here...
32 | |             .filter(|&p| p.exists() && p.is_file())
33 | |             .filter_map(|path| {
34 | |                 File::open(path).map_err(|e| {
35 | |                     writeln!(std::io::stderr(), "Failed to open {}: {}", path.display(), e)
36 | |                 }).ok()
37 | |             })
38 | |             .flat_map(EventReader::new)
   | |_______________________________________^ ...ending here
Denis Lisov
May 30 2017 19:55
@luolong Well, they really are: flat_map returns a specific iterator of EventReaders, while the first branch returns just an EventReader
I'd make it vec![EventReader::new(std::io::stdin())] and .flat_map(EventReader::new).collect() if you don't expect to have more than about a thousand of files :-)
Roland Tepp
May 30 2017 21:36
no, not really that many :)
Why wouldn’t rewriting None case like this help:
        None => std::iterator::once(EventReader::new(std::io::stdin())),
Denis Lisov
May 30 2017 21:47
You need both branches to be of the same type, but Once and FlatMap are different types, even though both implement Iterator. You can work this around by casting both to a trait object with some minor performance cost.