Rust gotcha: deriving Copy and Clone can be too restrictive
This is a very short post to share a Rust gotcha I recently discovered. It can be summed up in this TL;DR, freely adapted from the doc:
For a generic struct,
#[derive]
implements Clone (resp. Copy) conditionally by adding bound Clone (resp. Copy) on generic parameters, which isn't always desired.
The problematic situation can be seen in the following code:
#[derive(Clone, Copy)]
struct MyRef<'a,T>(&'a T);
fn main() {
// v is not Copy, but &v is
let v : Vec<()> = Vec::new();
// _r1 = &v; would compile
let _r1 = MyRef(&v);
// _r1 moves into _r2
// except if _r1 is copy
let _r2 = _r1;
// Error: use of moved value: _r1
_r1;
}
We would expect MyRef<'a,T>
to be Clone and Copy even if T
is not Clone or Copy, because it only contains &'a T
which is always Copy and Clone. But what the Rust compiler is deriving, is instead:
struct MyRef<'a, T>(&'a T);
impl<'a, T> Clone for MyRef<'a, T>
// Notice this bound
where
T: Clone,
{
fn clone(&self) -> Self {
MyRef((&self.0).clone())
}
}
impl<'a, T> Copy for MyRef<'a, T>
// Notice this bound
where T: Copy {}
In this case, we should rather implement Clone and Copy by hand, and remove the unneeded bounds like so:
struct MyRef<'a, T>(&'a T);
impl<'a, T> Clone for MyRef<'a, T>
{
fn clone(&self) -> Self {
MyRef((&self.0).clone())
}
}
impl<'a, T> Copy for MyRef<'a, T>
{}