How do I clone a closure, so that their types are

2020-02-02 01:32发布

问题:

I have a struct which looks something like this:

pub struct MyStruct<F>
where
    F: Fn(usize) -> f64,
{
    field: usize,
    mapper: F,
    // fields omitted
}

How do I implement Clone for this struct?

One way I found to copy the function body is:

let mapper = |x| (mystruct.mapper)(x);

But this results in mapper having a different type than that of mystruct.mapper.

playground

回答1:

You can't Clone closures. The only one in a position to implement Clone for a closure is the compiler... and it doesn't. So, you're kinda stuck.

There is one way around this, though: if you have a closure with no captured variables, you can force a copy via unsafe code. That said, a simpler approach at that point is to accept a fn(usize) -> f64 instead, since they don't have a captured environment (any zero-sized closure can be rewritten as a function), and are Copy.



回答2:

As of Rust 1.26.0, closures implement both Copy and Clone if all of the captured variables do:

#[derive(Clone)]
pub struct MyStruct<F>
where
    F: Fn(usize) -> f64,
{
    field: usize,
    mapper: F,
}

fn main() {
    let f = MyStruct {
        field: 34,
        mapper: |x| x as f64,
    };
    let g = f.clone();
    println!("{}", (g.mapper)(3));
}


回答3:

You can use Rc (or Arc!) to get multiple handles of the same unclonable value. Works well with Fn (callable through shared references) closures.

pub struct MyStruct<F> where F: Fn(usize) -> f64 {
    field: usize,
    mapper: Rc<F>,
    // fields omitted
}

impl<F> Clone for MyStruct<F>
    where F: Fn(usize) -> f64,
{
    fn clone(&self) -> Self {
        MyStruct {
            field: self.field,
            mapper: self.mapper.clone(),
           ...
        }
    }
}

Remember that #[derive(Clone)] is a very useful recipe for Clone, but its recipe doesn't always do the right thing for the situation; this is one such case.



回答4:

You can use trait objects to be able to implement Сlone for your struct:

use std::rc::Rc;

#[derive(Clone)]
pub struct MyStructRef<'f>  {
    field: usize,
    mapper: &'f Fn(usize) -> f64,
}


#[derive(Clone)]
pub struct MyStructRc  {
    field: usize,
    mapper: Rc<Fn(usize) -> f64>,
}

fn main() {
    //ref
    let closure = |x| x as f64;
    let f = MyStructRef { field: 34, mapper: &closure };
    let g = f.clone();
    println!("{}", (f.mapper)(3));
    println!("{}", (g.mapper)(3));

    //Rc
    let rcf = MyStructRc { field: 34, mapper: Rc::new(|x| x as f64 * 2.0) };
    let rcg = rcf.clone();
    println!("{}", (rcf.mapper)(3));
    println!("{}", (rcg.mapper)(3));    
}


标签: rust closures