Reputation: 853
Minimum example:
use std::collections::HashSet;
struct Something {
a: HashSet<Point>,
b: HashSet<Point>
}
impl Something {
fn TEST(&self) {
let new = self.a | self.b;
}
}
#[derive(Eq, PartialEq, Hash, Copy, Clone)]
struct Point {
x: usize,
y: usize
}
Check it on the Rust Playground. If you try and compile this code, Rust will complain with error[E0369]: no implementation for std::collections::HashSet<Point> | std::collections::HashSet<Point>
.
But according to the docs for HashSet, at least according to my understanding, the BitOr
trait should be implemented for a HashSet, where T: Eq + Hash + Clone
, which Point
clearly is here. So what's actually going on, and how do I fix it?
Upvotes: 3
Views: 478
Reputation: 14434
Taking a closer look at the implemention of BitOr
for HashSet
:
impl<T, S> BitOr<&HashSet<T, S>> for &HashSet<T, S>
where
...
BitOr
is only implemented for references to HashSet
s, not for owned values.
Re-writing your implementation for Something::TEST
as follows will compile as expected.
impl Something {
fn TEST(&self) {
let new = &self.a | &self.b;
}
}
Note that this uses references to self.a
and self.b
.
The fact that operations like bitwise-or are only implemented for references to containers instead of for the the container types themselves may seem unexpected at first, but it makes perfect sense when you think about their expected ownership semantics. The signature of bitor
is fn bitor(self, rhs: T)
, which takes ownership of both self
and rhs
. If BitOr
(or any other binary operator trait) were implemented directory a type that isn't Copy
, then it would be taking ownership of the arguments to |
. Having a | b
resulting in either a or b being moved would be rather unexpected. As such, the standard library only implements binary operators for references to collections (which are Copy
able) rather than on collection values themselves.
Upvotes: 5