6

When I try to extend a HashSet<String> with another HashSet<String>:

use std::collections::HashSet;
let mut a = HashSet::new();
a.insert("foo".to_owned());
let mut b = HashSet::new();
b.insert("bar".to_owned());
let c = a.extend(&b);

I get:

error[E0271]: type mismatch resolving `<&HashSet<String> as IntoIterator>::Item == String`
 --> src/main.rs:7:11
  |
7 | let c = a.extend(&b);
  |           ^^^^^^ expected reference, found struct `String`
  |
  = note: expected reference `&String`
                found struct `String`

How do I do this?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Simon Morgan
  • 2,018
  • 5
  • 23
  • 36
  • 3
    The accepted answer to the other question doesn't address what's asked here because it recommends `a.extend(&b)` which fails for the OP. It works in the other answer because the other answer uses set elements that are `Copy`. (I was sort of surprised that `a.extend(&b) works for `Copy` elements, I wonder what mechanism allows it.) – user4815162342 Feb 19 '21 at 21:53

1 Answers1

10

HashSet::extend() comes from the Extend trait and therefore accepts any iterator (or iterable), not just a set.

If you pass it the reference to a set, that reference is iterable, but the iterator produces references to the elements of the set - in this case &String. Since HashSet::<String>::extend() expects an iterator that produces actual strings, that doesn't compile. There are two ways to fix the issue:

  • by passing the set b to extend by value: a.extend(b);
  • by creating an explicit iterator out of b using b.iter() and cloning the values it produces: a.extend(b.iter().cloned()).

In the first variant, b will be consumed and therefore no longer usable by the caller, but the strings from it will be reused in a. In the second variant, b will remain usable, but its strings will be copied for storage in a.

Note that in neither variant does it make sense to capture the return value of extend(), since it operates by side effect and doesn't return a useful value.

user4815162342
  • 141,790
  • 18
  • 296
  • 355