如何克隆闭包,使它们的类型相同?



我有一个结构体,看起来像这样:

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

我如何实现这个结构的Clone ?

我发现复制函数体的一种方法是:
let mapper = |x| (mystruct.mapper)(x);

但这导致mappermystruct.mapper具有不同的类型。

游乐场

从Rust 1.26.0开始,如果所有捕获的变量都实现了CopyClone,闭包将同时实现:

#[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));
}

你不能Clone闭包。唯一能够实现闭包Clone的是编译器…它。所以,你有点被卡住了。

有一个方法可以解决这个问题:如果你有一个闭包,其中没有捕获的变量,你可以通过unsafe代码强制复制。也就是说,对于点,更简单的方法是接受fn(usize) -> f64 而不是,因为它们没有捕获环境(任何零大小的闭包都可以重写为函数),并且是Copy .

您可以使用Rc(或Arc !)来获得相同不可克隆值的多个句柄。可以很好地与Fn(可通过共享引用调用)闭包一起使用。

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(),
           ...
        }
    }
}

请记住,#[derive(Clone)]是克隆的一个非常有用的配方,但它的配方并不总是做正确的事情;

你可以使用trait对象来为你的struct实现Сlone:

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

最新更新