I'd like to have a struct, Quox
which can optionally have each type of closure that there can be( Fn
, FnMut
and FnOnce
) around. I typed it this way:
#[derive(Default, Debug)]
pub struct Quox<Tfn: Fn(&Person) + Sized, Tfnmut: FnMut(&mut Person) + Sized, Tfnonce: FnOnce(&Person) + Sized> {
soft_closure: Option<Tfn>,
mut_closure : Option<Tfnmut>,
move_closure: Option<Tfnonce>,
}
Now, when instantiating it i do it via Box
because Rust complains the trait Sized is not implemented for `dyn Fn()`rustcE0277
. (Maybe there is a better way or i misunderstand trait objects?):
pub fn main(){
let mut qx = Quox::<Box<dyn Fn(&Person)>, Box<dyn FnMut(&mut Person)>, Box<dyn FnOnce(&Person)>> {
move_closure: None,
mut_closure : None,
soft_closure: None,
};
...
}
qx
:
pub fn main(){
let mut qx = Quox::<Box<dyn Fn(&Person)>, Box<dyn FnMut(&mut Person)>, Box<dyn FnOnce(&Person)>> {
move_closure: None,
mut_closure : None,
soft_closure: None,
};
let greeting = "Hi. We are moving soon!".to_string();
let clsr_move = move |p:&Person| println!("Hi, {}. {} says: {}", p.name, p.name, greeting);
let only_a_ref_clsr = |p:&Person| println!("Hi, {}.",p.name );
// qx.move_closure = Some(Box::new(clsr_move)); // expected
// qx.soft_closure = Some(Box::new(only_a_ref_clsr)); // expected
qx.soft_closure = Some(Box::new(clsr_move)); // Why is this valid???
qx.move_closure = Some(Box::new(only_a_ref_clsr)); // Ok Fn is supertrait to FnOnce
}
Again, what's confusing is that i'm getting no error for trying to assign a (seemingly) FnMut
to Fn
.
Box
to an intermediary variable now throws error???
pub fn main(){
let mut qx = Quox::<Box<dyn Fn(&Person)>, Box<dyn FnMut(&mut Person)>, Box<dyn FnOnce(&Person)>> {
move_closure: None,
mut_closure : None,
soft_closure: None,
};
let greeting = "Hi. We are moving soon!".to_string();
let clsr_move = move |p:&Person| println!("Hi, {}. {} says: {}", p.name, p.name, greeting);
let only_a_ref_clsr = |p:&Person| println!("Hi, {}.",p.name );
let someboxmove = Some(Box::new(only_a_ref_clsr));
qx.soft_closure = someboxmove; // Invalid.
}
The error i'm getting is:
let someboxmove: Option<Box<|&Person| -> ()>>
Go to Option | Box | Person | Global
mismatched types
expected enum `Option<Box<dyn for<'r> Fn(&'r traitobjects::Person)>>`
found enum `Option<Box<[closure@src/traitobjects.rs:49:27: 49:66]>>`rustcE0308
traitobjects.rs(49, 27): the found closure
traitobjects.rs(66, 5): expected due to the type of this binding
Boiling down your first question:
let greeting = "Hi. We are moving soon!".to_string();
let clsr_move = move |p:&Person| println!("Hi, {}. {} says: {}", p.name, p.name, greeting);
let soft_closure: Box<dyn Fn(&Person)> = Some(Box::new(clsr_move));
There's no reason that clsr_move
can't be Fn
. The move
is for telling the compiler to move all captures into the closure, but what makes a closure strictly FnOnce
is if variables were moved out of the closure. This closure can obviously be called again and again.
Your second problem is simply a side-effect of Rust's type inference. If the type that Box::new()
should create is not immediately clear from the expression, then it will pick the type that was given to it; in the latter case the anonymous type of the closure. In the former, it can see that it is going to be assigned to something expecting a Box<dyn...>
and can preemptively coerce the type. So its simply the case that the inference algorithm does not look far enough ahead.
It also can't implicitly coerce a Option<Box<T>>
into a Option<Box<dyn Trait>>
. It could coerce a Box<T>
into a Box<dyn Trait>
, but since these have different sizes and layouts it doesn't extend as a generic parameter for Option
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.