function A
which take a function B
as parameter, again the function B
take function C
as parameter. I try the syntax like below, but this gives me an error:
fn a(b: impl Fn(impl Fn() -> ()) -> ()) -> () {
// ...
}
error[E0666]: nested `impl Trait` is not allowed
--> src/main.rs:2:21
|
2 | fn a(b: impl Fn(impl Fn() -> ()) -> ()) -> () {
| --------^^^^^^^^^^^^^^^-------
| | |
| | nested `impl Trait` here
| outer `impl Trait`
For some reason, I can't use &dyn
keyword:
fn a(b: impl Fn(&dyn Fn() -> ()) -> ()) -> () {
// ...
}
Are there another ways to do this?
And I don't know why nested impl Trait
cause an error.
Nested impl Trait doesn't work because it hasn't been specified or implemented yet. Also, because it isn't very useful given how other parts of Rust work.
fn a(b: impl Fn(impl Fn() -> ()) -> ()) -> ()
can be written using full generic syntax as
fn a<B, C>(b: B) -> ()
where B: Fn(C) -> (),
C: Fn() -> ()
So what does that mean? It means that B
is something callable that takes an argument of something else callable. But the important thing here is in the concrete types. Specifically, B
doesn't take any callable with a compatible signature, but specifically a C
. What is C? Well, that's the issue. If you call a
like this:
a(|f| f());
then C
is the type of the lambda's parameter f
, but that type is not known, since the parameter f
's type cannot be deduced from usage alone. But suppose that wasn't a problem, what would the body of a
look like?
fn a<B, C>(b: B) -> ()
where B: Fn(C) -> (),
C: Fn() -> () {
b(|| ())
}
Here we attempt to call b
passing lambda. But the lambda's type is unnamed local lambda type
, not C
. Since C
was passed in from the outside, it cannot be the type of a lambda local to a
. Simply put, unless you pass in a C
as an additional parameter to a
, there is nothing that a
has that it could pass to b
.
What you apparently want is for B
to be not a function object that can be called with some C
, but with any C
. You want it to be a polymorphic function object. Rust doesn't support compile-time polymorphic function objects (the equivalent in Haskell would be a forall a. a -> IO ()
or similar). It only supports runtime polymorphic function objects.
That's the job of dyn
. Now you've said you can't use &dyn
, because you want to pass the function object to another thread. So instead, use Box<dyn>
:
fn a(b: impl Fn(Box<dyn Fn() -> ()>) -> ()) -> () {
b(Box::new(|| println!("Hello")))
}
fn main() {
a(move |f| { f(); f(); });
}
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