#[derive(Default, Serialize, Deserialize, Debug, Eq, Hash, PartialEq)]
pub struct Component {
    name: String,
    module: String,
    r#type: String,
    url: String,
    hash: Option<String>,
    #[serde(skip)]
    retied_times: i8,
}

struct Tasks<'a, F>
where
    F: Future<Output = Result<()>>,
{
    foo: fn(&'a str, &'a Component) -> F,
}

impl<'a, F> Tasks<'a, F>
where
    F: Future<Output = Result<()>>,
{
    pub async fn call(&self, target_dir: &'a str, component: &'a Component) {
        (task)(target_dir, component).await;
    }
}
pub async fn process(target_dir: &str, component: &Component) {
    let task = Tasks { foo: download };
    task.call(target_dir, component);
}

async fn download(target_dir: &str, component: &Component) -> Result<()> {
    //...
}

这段代码将工作得很好.

但是,当我删除 struct Tasks中的生存期'a时,我将不会编译. 编译错误为:

 --> src/lib.rs:28:29
   |
28 |     let task = Tasks { foo: download };
   |                             ^^^^^^^^ one type is more general than the other
   |
   = note: expected fn pointer `for<'r, 's> fn(&'r str, &'s component::Component) -> _`
                 found fn item `for<'r, 's> fn(&'r str, &'s component::Component) -> impl Future<Output = Result<(), anyhow::Error>> {download}`

为什么会发生这种事?

推荐答案

由异步函数返回的future 捕获其所有生存期参数.即,以下内容:

async fn download(target_dir: &str, component: &Component) -> Result<()> {
    // ...
}

实际上是以下各项的快捷方式:

fn download<'a, 'b>(target_dir: &'a str, component: &'b Component) -> impl Future<Output = Result<()>> + 'a + 'b {
    async move {
        // ...
    }
}

也就是说,future 也是在一生中被参数化的.

当您在Tasks中使用'a时,您将用'a实例化download.也就是说,Tasks { foo: download }实际上是Tasks { foo: download::<'a, 'a> }(不是有效的Rust,但概念很清楚).它返回的future 类型也实例化为'a.所以你有一个具体的类型fn(&'a str, &'a Component),和一个具体的future 类型.这很好用.

但是,当您将'a保留在室外时,fnFuture类型仍然是参数类型.对于fn类型,这不是问题:我们可以使用更高级别的特征界限(for<'a, 'b> fn(&'a str, &'b Component),或仅使用生命周期省略fn(&str, &Component))来指定它.但对于future 类型,我们不能将其表述为参数(至少不容易;但请参见here).这就是您看到的错误:编译器期望F是一个具体的future 类型,但却得到了一个参数("更通用")类型.

Rust相关问答推荐

即使参数和结果具有相同类型,fn的TypId也会不同

当rust中不存在文件或目录时,std::FS::File::Create().unwire()会抛出错误

Box::new()会从一个堆栈复制到另一个堆吗?

定义采用更高级类型泛型的性状

你是如何在铁 rust 一侧的金牛座获得应用程序版本的?

如何导入crate-type=[";cdylib;]库?

如何定义实现同名但返回类型不同的 struct 的函数

如何将单个 struct 实例与插入器一起传递到Rust中的映射

将特征与具有生命周期的关联类型一起使用时的生命周期方差问题

随机函数不返回随机值

为什么某些类型参数仅在特征边界中使用的代码在没有 PhantomData 的情况下进行编译?

通过写入 std::io::stdout() 输出不可见

返回迭代器考虑静态生命周期类型

在给定 Rust 谓词的情况下,将 Some 转换为 None 的惯用方法是什么?

通用函数中的生命周期扣除和borrow (通用测试需要)

为什么可以从闭包中返回私有 struct

当用作函数参数时,不强制执行与绑定的关联类型

如何为枚举中的单个或多个值返回迭代器

Rust 内联 asm 中的向量寄存器:不能将 `Simd` 类型的值用于内联汇编

如何在 Rust 的泛型函​​数中同时使用非拥有迭代器和消费迭代器?