I was able to make this code work:
fn twice<T: Clone>(fst: impl Fn(T), snd: impl Fn(T)) -> impl Fn(T) {
move |t| {
fst(t.clone());
snd(t)
}
}
However, what I want is this (without boxing):
fn sub<T: Clone>(mut fst: impl Fn(T), snd: impl Fn(T)) {
fst = move |t: T| {
fst(t.clone());
snd(t)
};
}
Is there a way I can make the second piece of code work without boxing, using traits, type casting or any other method? Rust complains that the types do not match.
This cannot be done without boxing. The reason is that the actual type of fst
in the input is different than the type of the closure that you later overwrite it with. The only way to make them the same type is with a trait object.
The boxed version might look like this:
use std::mem;
fn sub<'a, T: Clone + 'a>(fst: &mut Box<dyn Fn(T) + 'a>, snd: impl Fn(T) + 'a) {
// Replace the original fst with a dummy closure while the new closure is being
// constructed, to avoid the reference being temporarily invalid
let fst_orig = mem::replace(fst, Box::new(|_| {}));
*fst = Box::new(move |t: T| {
fst_orig(t.clone());
snd(t)
});
}
fn main() {
let mut f1: Box<dyn Fn(i32)> = Box::new(|x| println!("f1: {}", x));
let f2 = |x| println!("f2: {}", x);
sub(&mut f1, f2);
f1(42);
}
But I really am not sure why you would want to do this!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With