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

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.