3
votes

The following code does not work because the Clone trait is not implemented for the type fn(&u16):

#[derive(Clone)]
struct FStruct(fn(&u16));

fn fn1(x:&u16){
    println!("fn1 called! {:?}", x);
}

fn fn2(x:&u16){
    println!("fn2 called! {:?}", x);
}

fn main() {

    let d1 = 32u16;
    let d2 = 42u16;

    let x1 = FStruct(fn1);
    let mut x2 = FStruct(fn2);

    x1.0(&d1); x2.0(&d2);

    x2 = x1.clone();//error: the trait `core::clone::Clone` is not implemented for the type `fn(&u16)`

    x1.0(&d1); x2.0(&d2);
}

I can implement it by myself of course:

impl Clone for FStruct{
    fn clone(&self) -> Self{
        unsafe{
            let mut t: FStruct = std::mem::uninitialized();
            std::ptr::copy_nonoverlapping(self, &mut t, 1);
            t      
        }
    }
}

But it is a bit annoying. Rust allows implementing Clone only for user types, so I need a struct or enum around fn(&T).

Is this implementation really safe to use? Why is Clone not implemented for fn(&T) by default?

1

1 Answers

8
votes

The "why" is pretty simple: issue 28229 wasn't fixed until Rust 1.21.0. Since that version, your code compiles.

Before that, due to a quirk of history, fn pointers do implement Copy, even though they don't implement Clone (and despite this being blatantly impossible). As a result, you can do this:

impl Clone for FStruct {
    fn clone(&self) -> Self {
        FStruct(self.0)
    }
}

Which is safe and easier to understand.