Rust won't compile the following:
#[derive(Copy, Clone)]
struct WhateverStruct<T> {
field : T
}
trait WhateverStructTrait<T> {
fn to(self) -> WhateverStruct<T>;
}
impl<T> WhateverStructTrait<T> for *mut WhateverStruct<T> {
fn to(self) -> WhateverStruct<T> {
unsafe {* self }
}
}
fn test() {
let x = WhateverStruct { field : 7u32 };
let _y = x;
let _z = x;
println!("Copying is fine");
}
fn main() {
test();
}
It complains on the unsafe {* self }
part saying that
*self
has typeWhateverStruct<T>
, which does not implement theCopy
trait
However, it quite clearly does implement the copy trait. The test function has no errors. If you change struct WhateverStruct<T> { field : T }
into struct WhateverStruct { field : u32 }
and remove the <T>
from the rest of the code, everything compiles and runs just fine. So Rust isn't liking the generic.
Here you can see on the playground : https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5d5c3a0f0e6e0153ec286ce38f0f3a2d
Is this a bug? Is there a work around?
For any generic type Foo<T>
when you derive Copy
and Clone
, the traits always have T
bound to be Copy
or Clone
respectively. Sometimes, though you don't actually need T
to implement those traits for the struct as a whole to be Copy
or Clone
.
An example of this is the following struct.
#[derive(Copy, Clone)]
struct Foo<T> {
_marker: std::marker::PhantomData<T>,
}
If we look at the code that the derive generates (cargo-expand
works for that purpose) we get something like
use std::prelude::v1::*;
#[macro_use]
extern crate std;
struct Foo<T> {
_marker: std::marker::PhantomData<T>,
}
#[automatically_derived]
#[allow(unused_qualifications)]
impl<T: ::core::marker::Copy> ::core::marker::Copy for Foo<T> {}
#[automatically_derived]
#[allow(unused_qualifications)]
impl<T: ::core::clone::Clone> ::core::clone::Clone for Foo<T> {
#[inline]
fn clone(&self) -> Foo<T> {
match *self {
Foo {
_marker: ref __self_0_0,
} => Foo {
_marker: ::core::clone::Clone::clone(&(*__self_0_0)),
},
}
}
}
Looking at just the implementation of Copy
(and cleaning up things a bit) it's
impl<T: Copy> Copy for Foo<T> {}
So even though Foo<T>
doesn't need T
to be Copy
, it restricts it anyway.
In these cases, you'll want to simply implement Copy
and Clone
yourself. There's a fairly trivial implementation that works as long as the actual fields of the struct are Copy
.
struct Foo<T> {
_marker: std::marker::PhantomData<T>,
}
impl<T> Copy for Foo<T> {}
impl<T> Clone for Foo<T> {
fn clone(&self) -> Self {
*self
}
}