Help! One type is more general than the other

i got error about this code, how to solve it without change lifetime and async

pub struct Data<'a>(&'a str);

async fn handle_data(_data: Data<'_>) {}

fn run<T>(_func: fn(Data) -> T) {}

fn main() {
    run(handle_data);
}

error[E0308]: mismatched types
   --> src/main.rs:165:9
    |
165 |     run(handle_data);
    |     --- ^^^^^^^^^^^ one type is more general than the other
    |     |
    |     arguments to this function are incorrect
    |
    = note: expected fn pointer `for<'a> fn(Data<'a>) -> _`
                  found fn item `for<'a> fn(Data<'a>) -> impl Future<Output = ()> {handle_data}`
note: function defined here
   --> src/main.rs:162:4
    |
162 | fn run<T>(_func: fn(Data) -> T) {}
    |    ^^^    --------------------

how to solve it without change lifetime and async

run needs to explicitly accept an async function:

fn run<T>(_func: impl AsyncFn(Data) -> T) {}

(Note that this syntax is new in Rust 1.85, released just last week. If you get a compilation error, make sure you have updated your Rust toolchain.)

2 Likes

wow, it's very nice, thank you.

hi, i got another error about the code:

#![allow(unused)]
pub struct Data<'a>(&'a str);

async fn handle_data(_data: Data<'_>) {}

fn run<T>(_func: impl AsyncFn(Data) -> T + Send + 'static)
where
    T: Send,
{
    let data = Data("data");
    tokio::spawn(_func(data));
}
error[E0277]: `<impl AsyncFn(Data) -> T + Send + 'static as AsyncFnMut<...>>::CallRefFuture<'_>` cannot be sent between threads safely
   --> src/main.rs:168:18
    |
168 |     tokio::spawn(_func(data));
    |     ------------ ^^^^^^^^^^^ `<impl AsyncFn(Data) -> T + Send + 'static as AsyncFnMut<...>>::CallRefFuture<'_>` cannot be sent between threads safely
    |     |
    |     required by a bound introduced by this call
    |
    = note: the full name for the type has been written to '/home/aksjfds/codes/hello/target/debug/deps/hello-50c3baf763c528c9.long-type-11855980535132875112.txt'
    = note: consider using `--verbose` to print the full type name to the console
    = help: the trait `Send` is not implemented for `<impl AsyncFn(Data) -> T + Send + 'static as AsyncFnMut<...>>::CallRefFuture<'_>`
note: required by a bound in `tokio::spawn`
   --> /home/aksjfds/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.43.0/src/task/spawn.rs:168:21
    |
166 |     pub fn spawn<F>(future: F) -> JoinHandle<F::Output>
    |            ----- required by a bound in this function
167 |     where
168 |         F: Future + Send + 'static,
    |                     ^^^^ required by this bound in `spawn`
help: introduce a type parameter with a trait bound instead of using `impl Trait`
    |
163 ~ fn run<T, A: AsyncFn(Data) -> T + Send + 'static>(_func: A)
164 | where
165 ~     T: Send, <A as AsyncFnMut<(Data<'_>,)>>::CallRefFuture<'_>: Send
    |

If you need a Send bound you’ll need a messier solution not using AsyncFn. But are you sure you want to do this at all? You won't be able to take advantage of Data's lifetime because tokio::spawn requires the spawned task to be 'static, so you can only pass a Data<'static> that contains a &'static str. You may need a redesign.

i already give it up, it's complex that will spend more time,
no matter how, thank you