DanielV
DanielV

Reputation: 663

Rust, Copy Trait not working with a type when it uses generic

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 type WhateverStruct<T>, which does not implement the Copy 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?

Upvotes: 4

Views: 2719

Answers (2)

Debabrata Bardhan
Debabrata Bardhan

Reputation: 47

I think you have just missed a small thing that is trait bound. The genetic type T must implement(or derive) the Copy and Clone Traits so what you need to do is, just add Copy and Clone as a trait bound in impl

your implementation block would be just

impl<T:Copy+Clone> WhateverStructTrait<T> for *mut WhateverStruct<T> {
    fn to(self) -> WhateverStruct<T> {
        unsafe {* self }
    }
}

Rest of the code should be kept as it is.

Upvotes: 0

SCappella
SCappella

Reputation: 10424

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
    }
}

Upvotes: 11

Related Questions