I have a closure, and a function my_fun that does something with it (playground):
pub trait Message { /* not important */ }
struct MyMessage { /* not important */ }
impl Message for MyMessage { /* not important */ }
pub fn my_fun<Req, Resp, F>(
f: Box<F>,
) -> Result<Vec<u8>, String>
where
Req: Message,
Resp: Message,
F: (FnOnce(&Req) -> Result<Resp, String>)
{
unimplemented!(/* not important */)
}
pub fn main() {
let router: Box<Fn(&MyMessage) -> Result<MyMessage, String> + Send>;
router = Box::new(|message| unimplemented!(/* not important */));
my_fun(router);
}
But alas
error[E0277]: the size for values of type `dyn for<'r> std::ops::Fn(&'r MyMessage) -> std::result::Result<MyMessage, std::string::String> + std::marker::Send` cannot be known at compilation time
--> src/main.rs:21:9
|
21 | my_fun(router);
| ^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r MyMessage) -> std::result::Result<MyMessage, std::string::String> + std::marker::Send`
= note: to learn more, visit <doc.rust-lang.org/book/second-edition/ch19-04-adv…
note: required by `my_fun`
I know Fn or FnOnce isn't Sized, that's why I Boxed it. Why is it still a problem?
Or is it complaining about my_fun? Why does it matter if my_fun is sized?
did you try adding the compound Type + Sized ?
or you could go full generic if I understand that correct: stackoverflow.com/questions/32618872/sized-is-not…
but I would have to experiment with it myself :) and I have to go to several meetings today :) So I'll try it out later for testing :) let me know if you solved it :)
tl;dr: You must be explicit in your definitions when adding type info. Instead of
Fn, which is a trait, you should usefn, which is a type.I am not a black Rust mage though, so here is what I did to find out what's wrong: First, I took the liberty to simplify the situation to a point which works:
pub trait Message{} struct MyMessage; impl Message for MyMessage {} pub fn my_fun<Req, F>(_f: F) -> Result<Vec<u8>, String> where Req: Message, F: (FnOnce(&Req) -> Result<Req, String>), { unimplemented!(); } pub fn main() { let _ = my_fun(|_message: &MyMessage| { unimplemented!(); }); }It's basically what you already have, sans the
Boxand the additional variable. Just passing the closure will handle it inline, so the compiler will do the thinking about how to handle sizing internally. Great. Let's get the closure in a variable, shall we!pub fn main() { let router = |_message: &MyMessage| { unimplemented!(); }; let _ = my_fun(router); }This code will compile, too. What magic did I do??? Simple. I remembered that the Rust compiler is very clever, so it will figure out the variable type on its own, just like before when I left out the variable. The lesson here: Everything's ok, however you declared the wrong type and traits explicitly, which made it impossible for the compiler to figure out the size. What would be the correct type signature, then, you ask? I am using IntelliJ, so I cheated a bit, because I get the type displayed implicitely, however the explicit code looks like this:
pub fn main() { let router: fn(&MyMessage) -> Result<MyMessage, String> = |_message: &MyMessage| { unimplemented!(); }; let _ = my_fun(router); }which you can also write as
pub fn main() { let router: fn(&MyMessage) -> Result<MyMessage, String>; router = |_message: &MyMessage| { unimplemented!(); }; let _ = my_fun(router); }I'd say, it's one of those instances, when Rust is a bit annoying. In the function you declared that the parameter should implement the trait
Fn, however, in the definition, you actually must be explicit. A trait does not have a size, however a type does! And which primitive type is used for functions? Right!fn. Check out Fn vs fn for more info on them.