20

While working with serde_json for reading json documents, I wrote the following line of code to obtain the result of unwrapping the return value of serde_json::from_str:

fn get_json_content(content_s: &str) -> Option<Value> {
    let ms: String = serde_json::from_str(content_s).unwrap; // <--

    match serde_json::from_str(content_s) {
        Ok(some_value) => Some(some_value),
        Err(_) => None
    }
}

As you can see, I forgot the () on the end of the call to unwrap, which resulted in the following error:

error: attempted to take value of method unwrap on type core::result::Result<_, serde_json::error::Error>

let ms: String = serde_json::from_str(content_s).unwrap;

But when I looked at this a bit further, the thing that struck me as odd was:

core::result::Result<_, serde_json::error::Error>

I understand what underscore means in a match context, but to instantiate a generic? So what does this mean? I couldn't find any answers in the Rust book, or reference, or a web search.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Plastikfan
  • 3,674
  • 7
  • 39
  • 54

1 Answers1

34

It's a placeholder. In this context, it means that there isn't enough information for the compiler to infer a type.

You can use this in your code to make the compiler infer the type for you. For example:

pub fn main() {
    let letters: Vec<_> = vec!["a", "b", "c"]; // Vec<&str>
}

This is particularly handy because in many cases you can avoid using the "turbofish operator":

fn main() {
    let bar = [1, 2, 3];
    let foos = bar.iter()
                  .map(|x| format!("{}", x))
                  .collect::<Vec<String>>(); // <-- the turbofish
}

vs

fn main() {
    let bar = [1, 2, 3];
    let foos: Vec<_> = bar // <-- specify a type and use '_' to make the compiler
                           //     figure the element type out
            .iter()
            .map(|x| format!("{}", x))
            .collect(); // <-- no more turbofish
}
Wesley Wiser
  • 9,491
  • 4
  • 50
  • 69
  • 2
    Thanks for that. I prefer to be explicit about all types, because omitting types to me just makes code unreadable, which is why I always specify types in let bindings. I know this is seems like an anti pattern in Rust, but I waste too much time in figuring out the types of things, so I'd rather be explicit. – Plastikfan May 13 '16 at 18:02
  • 2
    @Zephilim: There's an interesting argument about type elision; some argue types are necessary for understanding, others that they clutter the real information. It's a very personal choice in the end :) – Matthieu M. May 13 '16 at 18:09
  • Well you can guess what side of the argument I'm on. It wouldn't be so bad if I had a decent IDE that could go to the definition of things, but thats not my setup at the moment. I'm just using Atom as a text editor which can't do this. I tried VisualRust, but that's hopeless at the moment. – Plastikfan May 13 '16 at 18:14
  • 2
    FYI, for the turbofish, you could probably use `::>` instead of `::>`. – Solomon Ucko Apr 14 '20 at 03:20