Cannot infer type for `B` for filter_map().sum()

后端 未结 2 753
醉梦人生
醉梦人生 2020-12-21 08:02

The code below reads numbers, sums them, then prints the sum. I\'ve tried few annotations, but it didn\'t work. I must be missing something. How could I make it work?

<
相关标签:
2条回答
  • 2020-12-21 08:54

    Let's look up the signature of filter_map to see, what the complain is about:

    fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F> where F: FnMut(Self::Item) -> Option<B>, 
    

    Okay, so Option<B> is the result, which means he cannot infer what w.parse().ok() will be.

    Let's try to give him a hint

    .filter_map(|w| w.parse::<i32>().ok())
    

    Let's compile an see.... Hurray!

    So, lesson learned: Look up the signature and try to figure out, which part the compiler cannot infer and try to specify it.

    0 讨论(0)
  • 2020-12-21 09:04

    The quick fix is to say which type you are parsing into:

    let v: i32 = buff
        .split_whitespace()
        .filter_map(|w| w.parse::<i32>().ok())
        .sum();
    

    The reason is that filter_map has a type variable B, which would need to be inferred from the closure that you pass to it (the closure returns Option<B>). However, parse() also has a type variable for the type you are parsing into, which also can often be inferred. But here the type-checker would have to infer each of these types from each other, which obviously can't be done. To break the cycle, you have to tell it somewhere what the concrete type is.

    You also could have fixed it by annotating filter_map. It's not as nice because filter_map has two type parameters, but you can still let the second one be inferred by using an _:

    let v: i32 = buff
        .split_whitespace()
        .filter_map::<i32, _>(|w| w.parse().ok())
        .sum();
    
    0 讨论(0)
提交回复
热议问题