1

I was following some code examples on the Rust CSV crate's tutorial page, and the tutorial doesn't explain how this works:

type Record = HashMap<String, String>;

fn csv_to_record_table() -> Result<Vec<Record>, Box<dyn Error>> {
    let mut rdr = csv::Reader::from_path(r"h:\code\rust\csvtutorial\uspop.csv")?;
    let mut sheet = Vec::<Record>::new();
    for result in rdr.deserialize() {
        let record = result?;
        sheet.push(record);
    }
    Ok(sheet)
}

My code works, so I don't need a fix, but what I'm trying to understand is how rdr.deserialize() is able to infer that the type I want is HashMap<String, String>. I get from the documentation that if you pass it a hashmap, then it knows to use the column name as the key, and the field data as the value.

What I don't get is how rdr.deserialize() knows that that's what I'm trying to do without me rewriting that as rdr.deserialize::<Record>(). Is this a feature of Rust? Or is this something specific to Serde? How does it also know that I'm not trying to give it a Vec<Record>?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Dragoon
  • 723
  • 6
  • 13
  • 1
    You've specified that `sheet` is `Vec`, thus any value pushed into it must be `Record`. `deserialize` returns an iterator of `Result`, which you handle the error case, so `T` must be `Record`. – Shepmaster Sep 14 '20 at 19:04
  • See also [Why does calling a method on a variable prevent Rust from inferring the type of the variable?](https://stackoverflow.com/q/55243660/155423) – Shepmaster Sep 14 '20 at 19:04
  • You can *probably* write `Vec::new()` (no need for the type) as well. In fact, that whole thing can be `Ok(rdr.deserialize().collect()?)` – Shepmaster Sep 14 '20 at 19:05
  • interesting...I tried the rdr.deserialize().collect()? and it says that it can't infer the type for the .collect. This reminds me of linq but I don't understand the examples that well. And that is correct, removing the type from the Vec initalizer works. FWIW I have rust-analyzer and it's showing me what types it's inferring, just how it's doing that is confusing, I kind of feel like it makes the code hard to read without rust-analyzer – Dragoon Sep 14 '20 at 22:28
  • Odd, swear I tested that. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=be7564bbe493c034216af84accc10949 Works though – Shepmaster Sep 14 '20 at 22:33
  • That works. Is there something similar to .collect that could, say, collect this into a HashSet as opposed to Vic, similar to .Net's .ToHashSet, .ToArray, .ToList, etc, or would something like that need to be done with the for loop? – Dragoon Sep 14 '20 at 23:20
  • Yes, it’s called `collect`. Just change the `Vec` to `Hashset` – Shepmaster Sep 14 '20 at 23:32
  • I tried that, the compiler gave me this: the trait `std::hash::Hash` is not implemented for `std::collections::HashMap` – Dragoon Sep 14 '20 at 23:42
  • Ah, that’s a different problem. https://stackoverflow.com/q/27828487/155423 – Shepmaster Sep 14 '20 at 23:52
  • Thanks! By the way, I've since learned that instead of HashMap I could use BTreeMap, which implements .Hash, and so it can be placed in a HashSet. If I had enough knowhow with rust, I'd submit a pull request to add support for that in the IndexMap crate, which is better suited to what I'm doing. – Dragoon Sep 16 '20 at 00:37

0 Answers0