(See the @dkim's answer for a more official and cited answer)
If the signature of the function accepts by reference, it does not take ownership of the value. Option.is_some() actually takes &self not self.
The interesting part is how *self
is allowed to be used in a function that receives &self
when Self: Copy
is not bounded.
To test this, let's create a minimal example containing something similar: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=d7b137b74b5cd8f8bb57398ae01bf4e3
#[derive(Debug)]
pub enum A {
X(String),
Y(i32),
}
pub fn f(a: &A) {
match *a {
A::X(_) => {
// dbg!(s);
}
A::Y(_i) => {
// dbg!(i);
}
};
}
This compiles fine. But let's change the A::X(_)
pattern to A::X(_s)
: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=93030e5c3f84532532c5db966c798bd6
#[derive(Debug)]
pub enum A {
X(String),
Y(i32),
}
pub fn f(a: &A) {
match *a {
A::X(_s) => {
// dbg!(s);
}
A::Y(_i) => {
// dbg!(i);
}
};
}
This fails to compile:
error[E0507]: cannot move out of `a.0` which is behind a shared reference
--> src/lib.rs:7:11
|
7 | match *a {
| ^^ help: consider borrowing here: `&*a`
8 | A::X(_s) => {
| --
| |
| data moved here
| move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait
So it appears that dereferencing a non-Copy enum is perfectly fine, as long as it wouldn't be used for moving inner non-Copy values. _
is fine because it guarantees that the underlying value would never be used, while _s
does not compile because it is just a normal allow(unused) variable.
This also makes sense because it allows the same match arm to work on both Copy and non-Copy types, as long as no usages violate the ownership rules
impl<T> Copy for Option<T> where T: Copy
and the integer primitives are allCopy
. Therefore,Option<{integer}>
is alsoCopy
. – Wesley Wiser