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

后端 未结 4 1136
半阙折子戏
半阙折子戏 2020-12-07 03:51

I have a struct which looks something like this:

pub struct MyStruct
where
    F: Fn(usize) -> f64,
{
    field: usize,
    mapper: F,
    // fie         


        
相关标签:
4条回答
  • 2020-12-07 04:10

    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));
    }
    
    0 讨论(0)
  • 2020-12-07 04:10

    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.

    0 讨论(0)
  • 2020-12-07 04:12

    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.

    0 讨论(0)
  • 2020-12-07 04:27

    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));    
    }
    
    0 讨论(0)
提交回复
热议问题