9

I have a structure with a field which is a function pointer. I want to implement the Clone trait for that struct, but I can't because function pointers can't be cloned if they have at least one parameter:

fn my_fn(s: &str) {
    println!("in my_fn {}", s);
}

type TypeFn = fn(s: &str);

#[derive(Clone)]
struct MyStruct {
    field: TypeFn
}

fn main() {
    let my_var = MyStruct{field: my_fn};
    let _ = my_var.clone();
}

Link to playground.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Moebius
  • 6,242
  • 7
  • 42
  • 54

2 Answers2

8

Function pointers with references in their types don't implement Clone because of issue #24000. This means that you can't #[derive(Clone)] for types containing them; you have to implement it manually.

But function pointers are Copy, so you can impl Copy for your type and then use that to manually impl Clone:

impl Copy for MyStruct {}

impl Clone for MyStruct {
    fn clone(&self) -> Self { *self }
}

Playpen link.

mbrubeck
  • 869
  • 6
  • 5
  • 1
    This is a great idea, unfortunately it doesn't work if you're using `Box` since Box is not Copy. Looks like this might help; https://stackoverflow.com/questions/65203307/how-do-i-create-a-trait-object-that-implements-fn-and-can-be-cloned-to-distinct – Schneems Jan 23 '23 at 14:51
3

The problem is not that function pointers in general are not clonable, but that you actually have a function that is generic over the lifetime of the &str. For example if you replace the &str with i32 your code will compile, because i32 has no lifetimes. In your situation you need to make the lifetimes on the function pointer explicit:

type TypeFn<'a> = fn(s: &'a str);

This obviously bubbles up to the struct, too:

#[derive(Clone)]
struct MyStruct<'a> {
    field: TypeFn<'a>
}

This prevents the following kind of code:

let my_var = MyStruct{field: my_fn};
let s = String::new();
(my_var.field)(&s);

Actually the problem is that it's a bug. As shown in @MattBrubeck 's answer Function pointers implement Copy. So you can just implement Clone manually by using the function pointer's Copy impl:

impl Clone for MyStruct {
    fn clone(&self) -> Self {
        MyStruct {
            field: self.field,
        }
    }
}
Community
  • 1
  • 1
oli_obk
  • 28,729
  • 6
  • 82
  • 98
  • 1
    never mind me... The correct answer is it's a bug... I can't downvote my own post though ^^ and I cannot delete an answer that was accepted... – oli_obk Oct 31 '15 at 18:00
  • I used the method suggested by http://meta.stackoverflow.com/a/266154/1103681 . But feel free to change the accepted answer and leave a comment. Then I'll delete my answer. – oli_obk Oct 31 '15 at 18:21