Context: I'm about a month in to learning Rust, doing Advent of Code to help learn. Day three this year has a problem where part of the solution is a nice fit for intersecting three HashSets. Here is the code I ended up with.
I've extracted a minimal version of the error I got stuck at. I spent... an embarrassingly long time trying to get something working with .intersection(). This is what I expected to work based on understanding sets from other languages and reading the HashSet docs (and seeing lots of chained function calls in Rust).
use std::collections::HashSet;
fn main() {
let a: HashSet<_> = "vJrwpWtwJgWrhcsFMMfFFhFp".chars().collect();
let b: HashSet<_> = "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL".chars().collect();
let c: HashSet<_> = "PmmdzqPrVvPwwTWBwg".chars().collect();
let in_all = a
.intersection(&b)
.collect::<HashSet<_>>()
.intersection(&c)
.collect::<HashSet<_>>();
println!("{in_all:?}");
}
The current output is:
(all output is from 1.65.0 stable)
error[[E0308]](https://doc.rust-lang.org/stable/error-index.html#E0308): mismatched types
--> src/main.rs:11:23
|
11 | .intersection(&c)
| ------------ ^^ expected `&char`, found `char`
| |
| arguments to this function are incorrect
|
= note: expected reference `&HashSet<&char>`
found reference `&HashSet<char>`
note: associated function defined here
For more information about this error, try `rustc --explain E0308`.
I didn't understand how to easily affect the char references inside the HashSets.
I eventually ended up here, which works... but I knew wasn't right, and wouldn't work well for a larger number of sets.
use std::collections::HashSet;
fn main() {
let a: HashSet<_> = "vJrwpWtwJgWrhcsFMMfFFhFp".chars().collect();
let b: HashSet<_> = "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL".chars().collect();
let c: HashSet<_> = "PmmdzqPrVvPwwTWBwg".chars().collect();
let tmp1: HashSet<&char> = a.intersection(&b).collect();
let tmp2: HashSet<&char> = b.intersection(&c).collect();
let in_all: HashSet<&&char> = tmp1.intersection(&tmp2).collect();
println!("{in_all:?}");
}
I don't have specific proposed output, but I would have loved hints that lead me to one of the two solutions below.
I looked at some other folks solutions to the same problem notes and links here and with the caveat that I'm early in my Rust learning, here are the two outcomes I liked best:
Solution A
The solution I think I like best involves using operator sugar: HashSet implements &, which is clean and nearly what I expected intersection to work like. It's still awkward to give the extra &() reference in order to make the third intersection work. But, I'm probably missing some nice Rsut syntax, and I imagine there is a nice way to do this for the general case of a sequence of iteration. Maybe .fold() over an iterator or something?
use std::collections::HashSet;
fn main() {
let a: HashSet<_> = "vJrwpWtwJgWrhcsFMMfFFhFp".chars().collect();
let b: HashSet<_> = "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL".chars().collect();
let c: HashSet<_> = "PmmdzqPrVvPwwTWBwg".chars().collect();
let in_all = &(&a & &b) & &c;
println!("{in_all:?}");
}
output:
{'r'}
Solution B
Looking at other solutions, lots of folks used .copied()... and just adding that almost works... and the error message guides me to a working solution. (The message when adding .cloned() is similarly good)
use std::collections::HashSet;
fn main() {
let a: HashSet<_> = "vJrwpWtwJgWrhcsFMMfFFhFp".chars().collect();
let b: HashSet<_> = "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL".chars().collect();
let c: HashSet<_> = "PmmdzqPrVvPwwTWBwg".chars().collect();
let in_all = a
.intersection(&b)
.copied()
.collect::<HashSet<_>>()
.intersection(&c)
.collect::<HashSet<_>>();
println!("{in_all:?}");
}
output:
error[[E0716]](https://doc.rust-lang.org/stable/error-index.html#E0716): temporary value dropped while borrowed
--> src/main.rs:8:22
|
8 | let in_all = a
| ______________________^
9 | | .intersection(&b)
10 | | .copied()
11 | | .collect::<HashSet<_>>()
| |____________________________________^ creates a temporary which is freed while still in use
12 | .intersection(&c)
13 | .collect::<HashSet<_>>();
| - temporary value is freed at the end of this statement
14 |
15 | println!("{in_all:?}");
| ------ borrow later used here
|
help: consider using a `let` binding to create a longer lived value
|
8 ~ let binding = a
9 + .intersection(&b)
10 + .copied()
11 + .collect::<HashSet<_>>();
12 ~ let in_all = binding
|
For more information about this error, try `rustc --explain E0716`.
use std::collections::HashSet;
fn main() {
let a: HashSet<_> = "vJrwpWtwJgWrhcsFMMfFFhFp".chars().collect();
let b: HashSet<_> = "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL".chars().collect();
let c: HashSet<_> = "PmmdzqPrVvPwwTWBwg".chars().collect();
let binding = a.intersection(&b).copied().collect::<HashSet<_>>();
let in_all = binding.intersection(&c).collect::<HashSet<_>>();
println!("{in_all:?}");
}
Context: I'm about a month in to learning Rust, doing Advent of Code to help learn. Day three this year has a problem where part of the solution is a nice fit for intersecting three HashSets. Here is the code I ended up with.
I've extracted a minimal version of the error I got stuck at. I spent... an embarrassingly long time trying to get something working with
.intersection()
. This is what I expected to work based on understanding sets from other languages and reading the HashSet docs (and seeing lots of chained function calls in Rust).playground
The current output is: (all output is from 1.65.0 stable)
I didn't understand how to easily affect the char references inside the HashSets.
I eventually ended up here, which works... but I knew wasn't right, and wouldn't work well for a larger number of sets.
I don't have specific proposed output, but I would have loved hints that lead me to one of the two solutions below.
I looked at some other folks solutions to the same problem notes and links here and with the caveat that I'm early in my Rust learning, here are the two outcomes I liked best:
Solution A
The solution I think I like best involves using operator sugar: HashSet implements
&
, which is clean and nearly what I expected intersection to work like. It's still awkward to give the extra &() reference in order to make the third intersection work. But, I'm probably missing some nice Rsut syntax, and I imagine there is a nice way to do this for the general case of a sequence of iteration. Maybe.fold()
over an iterator or something?playground
output:
Solution B
Looking at other solutions, lots of folks used
.copied()
... and just adding that almost works... and the error message guides me to a working solution. (The message when adding.cloned()
is similarly good)playground
output:
And that works!:
playground
output: