异步函数作为异步函数的参数

问题描述 投票:0回答:1

我试图声明一个异步函数,它接受另一个异步函数作为参数,该函数必须通过不可变引用接受参数

仅举一个我想要的例子,这里是 js 代码:

async function wrapper(fun) {
    await fun("hello");
}

async function foo(some) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    console.log(some);
}

async function main() {
    await wrapper(foo)
}

main()

这就是我在 Rust 中尝试的:

use std::future::Future;
use tokio;

#[tokio::main]
async fn main() {
    wrapper(foo).await
}

async fn wrapper<F, Fut>(fun: F)
where
    F: Fn(&str) -> Fut,
    Fut: Future<Output = ()>,
{
    fun("hello").await;
}

async fn foo(some: &str) {
    tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
    println!("{}", some);
}

编译器给出这个错误:

error[E0308]: mismatched types
  --> src/main.rs:6:5
   |
6  |     wrapper(foo).await
   |     ^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected opaque type `impl for<'a> Future<Output = ()>`
              found opaque type `impl Future<Output = ()>`
   = help: consider `await`ing on both `Future`s
   = note: distinct uses of `impl Trait` result in different opaque types
note: the lifetime requirement is introduced here
  --> src/main.rs:11:20
   |
11 |     F: Fn(&str) -> Fut,
   |                    ^^^

For more information about this error, try `rustc --explain E0308`.
error: could not compile `fnhell` (bin "fnhell") due to 1 previous error

我感觉这个问题很容易解决,但我完全不知道他在说什么。

rust async-await rust-tokio
1个回答
0
投票

泛型类型的使用使编译器消息变得复杂,但关键部分是注释:“这里引入了生命周期要求”。

fun
采用一个字符串切片 (
&str
),它是对组成字符串的内存的引用,而不是内存本身。如果
&str
中的
fun
参数指向代码中其他位置的
String
,则
String
可能会超出范围,从而使
&str
无效。异步函数必须拥有其参数的所有权,因为在等待函数时可以随时删除引用的内存。

两个简单的修复。第一个是将参数类型更改为拥有的

String
并使用 to_string() 将硬编码的静态字符串切片“hello”转换为
String

async fn wrapper<F, Fut>(fun: F)
where
    F: Fn(String) -> Fut,
    Fut: Future<Output = ()>,
{
    fun("hello".to_string()).await;
}

async fn foo(some: String) {
    tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
    println!("{}", some);
}

或者,如果

fun
始终采用静态字符串切片,您可以将参数类型更改为
&'static str
,这表示字符串切片在程序的持续时间内有效。硬编码字符串始终是
&'static
(请参阅 Rust Book - 静态生命周期)。

async fn wrapper<F, Fut>(fun: F)
where
    F: Fn(&'static str) -> Fut,
    Fut: Future<Output = ()>,
{
    fun("hello").await;
}

async fn foo(some: &'static str) {
    tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
    println!("{}", some);
}
© www.soinside.com 2019 - 2024. All rights reserved.