0

I am running into the error when calling .partition() on a vector iterator:

error[E0277]: the trait bound `std::vec::Vec<std::result::Result<std::collections::HashSet<&std::string::String>, std::boxed::Box<dyn std::error::Error>>>: std::iter::Extend<&std::result::Result<std::collections::HashSet<std::string::String>, std::boxed::Box<dyn std::error::Error>>>` is not satisfied
 --> src/main.rs:9:24
  |
9 |         results.iter().partition(|r| r.is_ok());
  |                        ^^^^^^^^^ the trait `std::iter::Extend<&std::result::Result<std::collections::HashSet<std::string::String>, std::boxed::Box<dyn std::error::Error>>>` is not implemented for `std::vec::Vec<std::result::Result<std::collections::HashSet<&std::string::String>, std::boxed::Box<dyn std::error::Error>>>`
  |
  = help: the following implementations were found:
            <std::vec::Vec<T> as std::iter::Extend<&'a T>>
            <std::vec::Vec<T> as std::iter::Extend<T>>

When running the following code:

use std::collections::HashSet;

type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;

fn main() {
    let mut results: Vec<Result<HashSet<String>>> = Default::default();

    let (okays, errors): (Vec<Result<HashSet<&String>>>, Vec<_>) =
        results.iter().partition(|r| r.is_ok());
}

See playground for example.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Eidolon
  • 309
  • 3
  • 12
  • 1
    Wrong type: `.iter()` gives you an iterator of `&Result>`, not an iterator of `&Result>`. It's best to just let it infer the rest of the type. – E_net4 Aug 26 '20 at 16:45
  • 1
    The type specified for `okays` is wrong, it should be `Vec<&Result>>` (or alternatively just `Vec<_>`). `results.iter()` returns `impl Iterator>>`. – EvilTak Aug 26 '20 at 16:45
  • This appears to be a duplicate of your previous question — [The trait `rayon::iter::ParallelExtend` is not implemented for `std::vec::Vec](https://stackoverflow.com/q/63565121/155423) – Shepmaster Aug 26 '20 at 16:45

1 Answers1

1

As the error message states (with namespacing removed):

the trait Extend<&Result<HashSet<String>, Box<dyn Error>>> is not implemented for Vec<Result<HashSet<&String>, Box<dyn Error>>>

You can't extend a Vec<T> with elements of type &T because they aren't the same type.

Instead, you can do one of these:

  1. Change the type of the destination collection to Vec<&Result<HashSet<String>>> (or just Vec<_>, like your second destination type, to allow the compiler to infer the inner type).

  2. Convert the reference to an owned value, perhaps via clone or to_owned.

  3. Don't iterate over references to start with, using into_iter or drain instead.

However, your current type will be very hard or expensive to achieve, as you state that you want an owned Result with an owned HashMap but a reference the String.

I think the best thing is to use Itertools::partition_map and into_iter:

use itertools::Itertools; // 0.9.0
use std::collections::HashSet;

type Error = Box<dyn std::error::Error>;
type Result<T, E = Error> = std::result::Result<T, E>;

fn main() {
    let mut results: Vec<Result<HashSet<String>>> = Default::default();

    let (errors, okays): (Vec<_>, Vec<_>) = results.into_iter().partition_map(Into::into);
    // let (errors, okays): (Vec<Error>, Vec<HashSet<String>>)
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Side question, it appears as if I cannot call .reduce() on okays as it is a reference but neither .clone() or .to_owned() work? Any idea why this might be the case? – Eidolon Aug 26 '20 at 20:58
  • @Eidolon you can't call `reduce` [because there's no such method](https://doc.rust-lang.org/std/?search=reduce). – Shepmaster Aug 31 '20 at 14:06