0

The following block is library code; I can't edit it:

struct Container<F> {
    f: F,
}

fn wrapped<F, T>(f: F) -> Container<F>
where
    F: FnMut() -> T,
{
    Container { f }
}

I want a wrapper function that specializes T:

fn return_10() -> u32 {
    10
}

fn wrapper<F>() -> Container<F>
where
    F: FnMut() -> u32,
{
    wrapped(return_10)
}

fn main() {
    wrapper();
}

(For the sake of simplicity, I used u32 in the code above, but in reality I want to use a trait. I'm hoping that this doesn't matter.)

It doesn't work:

error[E0308]: mismatched types
  --> src/main.rs:20:13
   |
20 |     wrapped(return_10)
   |             ^^^^^^^^^ expected type parameter, found fn item
   |
   = note: expected type `F`
              found type `fn() -> u32 {return_10}`

Why can't Rust infer that T = u32? Am I supposed to not do this?

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
Yd Ahhrk
  • 1,088
  • 12
  • 24
  • I believe your question is answered by the answers of [“Expected type parameter” error in the constructor of a generic struct](https://stackoverflow.com/q/32551177/155423). If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jul 10 '18 at 18:19
  • TL;DR: `fn wrapper() -> Container u32> { wrapped(return_10) }` or `fn wrapper() -> Container u32> { wrapped(return_10) }` – Shepmaster Jul 10 '18 at 18:19
  • @Shepmaster Well, there's the issue that the ` T>` syntax does not seem to exist in the [manual](https://doc.rust-lang.org/book/second-edition/ch00-00-introduction.html) and I might have never have been able to find it if it weren't for the answers below... – Yd Ahhrk Jul 10 '18 at 19:35
  • @Shepmaster I did see that post and it did not help me; even now. – Yd Ahhrk Jul 10 '18 at 19:37

2 Answers2

4

When you write a function signature like this:

fn wrapper<F>() -> Container<F> 
where
    F: FnMut() -> u32;

It means:

For any type F that you choose, which implements FnMut() -> u32, I can give you a Container<F>.

If that was the case then you would be able to define some arbitrary struct, and have it implement FnMut() -> u32, and the wrapper function would have to somehow be able to conjure up an instance of it. That would be impossible - unless the FnMut trait also had a method to create new instances.

But luckily your code is doing something different. Rather than working for all possible types F, you just need it to work for one - the one that you know you'll return.

The way to describe that is with an impl Trait:

fn wrapper() -> Container<impl Fn() -> u32> {
    wrapped(return_10)
}

It means:

I'm going to return a Container<F>. F will implement Fn() -> u32 but I'm going to choose exactly what that concrete type is.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
1

I am not sure if this is what you're looking for but this code compiles.

struct Container<F> {
    f: F,
}

fn wrapped<F, T>(f: F) -> Container<F>
where
    F: FnMut() -> T,
{
    Container { f }
}

fn return_10() -> u32 {
    10
}

fn wrapper() -> Container<fn() -> u32> {
    wrapped(return_10)
}

fn main() {
    wrapper();
}

I figured this out by using the code below to force the compiler to spit out a message telling me the type it was expecting.

struct Container<F> {
    f: F,
}

fn wrapped<F, T>(f: F) -> Container<F>
where
    F: FnMut() -> T,
{
    Container { f }
}

fn return_10() -> u32 {
    10
}

fn main() {
    let x: () = wrapped(return_10);
}

When you compile the code above the compiler complains

error[E0308]: mismatched types
  --> src/main.rs:17:17
   |
17 |     let x: () = wrapped(return_10);
   |                 ^^^^^^^^^^^^^^^^^^ expected (), found struct `Container`
   |
   = note: expected type `()`
              found type `Container<fn() -> u32 {return_10}>`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user25064
  • 2,020
  • 2
  • 16
  • 28
  • Interesting. But how did you know that you could get this suggestion by assigning the result of `wrapped()`? The original error was pointing to the argument... which does appear in the same line... but is also kind of... "unrelated"? – Yd Ahhrk Jul 10 '18 at 19:47
  • 1
    Ah, well, I knew there was an issue with the return type of `wrapper` which must be the same as the return type of `wrapped(return_10)` – user25064 Jul 10 '18 at 20:23