Please read this code:
let func:Box<dyn Fn()>=Box::new(||{});
// func as Box<dyn FnMut()>; //ERROR!
Box::new(func) as Box<dyn FnMut()>; //OK
Why Rust requires me using Box
to wrap func
? Can I directly convert func
into Box<dyn FnMut()>
?
Please read this code:
let func:Box<dyn Fn()>=Box::new(||{});
// func as Box<dyn FnMut()>; //ERROR!
Box::new(func) as Box<dyn FnMut()>; //OK
Why Rust requires me using Box
to wrap func
? Can I directly convert func
into Box<dyn FnMut()>
?
You can't upcast to a dyn Supertrait
(yet).
You're getting a double indirection there via unsized coercion. Your outer Box
would call your inner Box
to call the closure.
Is there a particular reason you need the specific type? It's pretty common to just rely on generics:
fn call<F: FnMut()>(mut f: F) {
f();
}
fn main() {
let func: Box<dyn Fn()> = Box::new(|| {});
// This is fine without converting the type because
// `Box<dyn Fn()>` implements `FnMut()`
call(func);
}
Or, depending on the use case, you could maybe do something like this:
fn main() {
let closure = || {};
let func: Box<dyn Fn()> = Box::new(closure);
let funk: Box<dyn FnMut()> = Box::new(closure);
}
(Might not be possible if you're capturing state.)
You created a trait object by boxing the original closure. I don't believe that trait objects can be upcasted in such a way.
You're right, but I using convert ||{}
into Box<dyn Fn()>
in this example is just for convenient to explain the problem, in actual scenario func
was stored in a Vec
that I don't know what type it actually is. I'll choose another way to implement it. Thank you .
Note that if you really need to, you can write your own upcasting:
trait MyFn : Fn() {
fn into_dyn_fn_mut<'slf> (self: Box<Self>)
-> Box<dyn 'slf + FnMut()>
where
Self : 'slf,
;
}
impl<F : Fn()> MyFn for F {
fn into_dyn_fn_mut<'slf> (self: Box<Self>)
-> Box<dyn 'slf + FnMut()>
where
Self : 'slf,
{
self
}
}
fn main ()
{
let func: Box<dyn MyFn> = Box::new(|| {});
func();
let _: Box<dyn FnMut()> = func.into_dyn_fn_mut();
}
Thanks a lot, it works!
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.