你能克隆一个闭包吗?

2024-05-09

A FnMut由于显而易见的原因,闭包无法被克隆,但是Fn闭包具有不可变的范围;有没有办法创建一个“重复”Fn关闭?

尝试克隆它会导致:

error[E0599]: no method named `clone` found for type `std::boxed::Box<std::ops::Fn(i8, i8) -> i8 + std::marker::Send + 'static>` in the current scope
  --> src/main.rs:22:25
   |
22 |             fp: self.fp.clone(),
   |                         ^^^^^
   |
   = note: self.fp is a function, perhaps you wish to call it
   = note: the method `clone` exists but the following trait bounds were not satisfied:
           `std::boxed::Box<std::ops::Fn(i8, i8) -> i8 + std::marker::Send> : std::clone::Clone`

以某种方式将原始指针传递给Fn周围,​​如:

let func_pnt = &mut Box<Fn<...> + Send> as *mut Box<Fn<...>>

从技术上讲,上述方法是有效的,但看起来很奇怪。

这是我正在尝试做的一个例子:

use std::thread;

struct WithCall {
    fp: Box<Fn(i8, i8) -> i8 + Send>,
}

impl WithCall {
    pub fn new(fp: Box<Fn(i8, i8) -> i8 + Send>) -> WithCall {
        WithCall { fp: fp }
    }

    pub fn run(&self, a: i8, b: i8) -> i8 {
        (self.fp)(a, b)
    }
}

impl Clone for WithCall {
    fn clone(&self) -> WithCall {
        WithCall {
            fp: self.fp.clone(),
        }
    }
}

fn main() {
    let adder = WithCall::new(Box::new(|a, b| a + b));
    println!("{}", adder.run(1, 2));

    let add_a = adder.clone();
    let add_b = adder.clone();

    let a = thread::spawn(move || {
        println!("In remote thread: {}", add_a.run(10, 10));
    });

    let b = thread::spawn(move || {
        println!("In remote thread: {}", add_b.run(10, 10));
    });

    a.join().expect("Thread A panicked");
    b.join().expect("Thread B panicked");
}

我有一个带有盒装闭包的结构,我需要将该结构传递给多个线程。我不能,但我也无法克隆它,因为你无法克隆一个Box<Fn<>>并且你无法克隆&Fn<...>.


生锈 1.26

闭包同时实现Copy and Clone如果所有捕获的变量都这样做。您可以重写代码以使用泛型而不是盒装特征对象来克隆它:

use std::thread;

#[derive(Clone)]
struct WithCall<F> {
    fp: F,
}

impl<F> WithCall<F>
where
    F: Fn(i8, i8) -> i8,
{
    pub fn new(fp: F) -> Self {
        WithCall { fp }
    }

    pub fn run(&self, a: i8, b: i8) -> i8 {
        (self.fp)(a, b)
    }
}

fn main() {
    let adder = WithCall::new(|a, b| a + b);
    println!("{}", adder.run(1, 2));

    let add_a = adder.clone();
    let add_b = adder;

    let a = thread::spawn(move || {
        println!("In remote thread: {}", add_a.run(10, 10));
    });

    let b = thread::spawn(move || {
        println!("In remote thread: {}", add_b.run(10, 10));
    });

    a.join().expect("Thread A panicked");
    b.join().expect("Thread B panicked");
}

Rust 1.26 之前

请记住,闭包捕获了它们的环境,因此它们有自己的基于环境的生命周期。不过,您可以参考Fn*并进一步传递它们,或将它们存储在结构中:

fn do_more<F>(f: &F) -> u8
where
    F: Fn(u8) -> u8,
{
    f(0)
}

fn do_things<F>(f: F) -> u8
where
    F: Fn(u8) -> u8,
{
    // We can pass the reference to our closure around,
    // effectively allowing us to use it multiple times.
    f(do_more(&f))
}

fn main() {
    let val = 2;
    // The closure captures `val`, so it cannot live beyond that.
    println!("{:?}", do_things(|x| (x + 1) * val));
}

我想说的是,转换Fn*出于生命周期的考虑,将其传递给原始指针并将其传递。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

你能克隆一个闭包吗? 的相关文章

随机推荐