PhantomData interacts with Copy in a surprising way:
use std::marker::PhantomData;
#[derive(Copy, Clone)]
pub struct Seconds;
pub struct Meters;
#[derive(Copy, Clone)]
pub struct Val<T> {
pub v: PhantomData<T>
}
fn main() {
let v1: Val<Seconds> = Val {v: PhantomData};
let v2 = v1;
let v3 = v1;
let v4: Val<Meters> = Val {v: PhantomData};
let v5 = v4;
let v6 = v4;
}
This fails as follows:
src/main.rs:20:13: 20:15 error: use of moved value: `v4` [E0382]
src/main.rs:20 let v6 = v4;
^~
src/main.rs:19:13: 19:15 note: `v4` moved here because it has type `Val<Meters>`, which is moved by default
src/main.rs:19 let v5 = v4;
I'd thought that deriving Copy for Val<Meters> would give Val<Meters> copy semantics. But apparently, that's true only where Val's type parameter T also implements Copy. I don't understand why.
PhantomData always implements Copy, regardless of whether its type parameter does. And anyhow, if PhantomData<Meters> didn't implement Copy, I'd expect the compiler to complain that it couldn't derive Copy for Val<Meters>. Instead, the compiler happily derives Copy for Val<Meters>, yet it applies move semantics.
Is this behavior intentional? If so, why?
I'd thought that deriving Copy for
Val<Meters>would giveVal<Meters>copy semantics.
But Copy isn't being derived for Val<Meters>, just for all Val<T> where T itself is Copy.
There are several open issues on Github for this, e.g. this one. My impression is that this is not intentional, but just a limitation of the way derive currently works.
You can work around this by manually writing a blanket impl for Clone and Copy:
impl <T> Clone for Val<T> {
fn clone(&self) -> Val<T> {
Val {v: PhantomData}
}
}
impl <T> Copy for Val<T> {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With