类型擦除返回异步块的闭包

Type erasure of a closure that returns an async block

提问人:mallwright 提问时间:6/29/2023 更新时间:6/29/2023 访问量:48

问:

请考虑以下返回异步块的闭包:

|entity: &mut Entity| async move {
    entity.foo().await;
}

是否可以在不指定该枚举的泛型类型或生存期的情况下键入擦除并将此闭包存储在枚举中?考虑以下 MWE:

use std::future::Future;

struct Entity;
impl Entity {
    async fn foo(&mut self) {} 
}

fn main() {
    erase_and_store(|entity: &mut Entity| async move {
        entity.foo().await;
    });
}

fn erase_and_store<'a, C, F>(closure: C) -> Task where
    C: FnOnce(&'a mut Entity) -> F,
    F: Future<Output = ()> + 'a {
    
    Task::Variant(/* TODO convert closure to something that can be stored */)
}

enum Task {
    Variant(/* TODO store closure */)
}

我尝试了几种不同的方法,但似乎即使我把所有东西都放在盒装特征对象后面,我也无法阻止这个通用生命周期泄漏到我的枚举中。'aTask

type AnyFuture<'a> = Box<dyn Future<Output = ()> + 'a>;
type AnyClosure<'a> = Box<dyn FnOnce(&'a mut Entity) -> AnyFuture<'a>>;

enum Task {
    Variant(AnyClosure) // requires <'a>
}
异步 Rust 闭包

评论

1赞 isaactfa 6/29/2023
(1)未来并不意味着它不借东西。你可以随心所欲地得到结果,它仍然会借用。(2) 不返回 ed 任何东西,它返回一个实现 .在闭包返回类型位置稳定之前,您不能在没有泛型的情况下命名该类型。BoxBoxentity.fooentityerase_and_storeBoxFutureimpl Trait
0赞 mallwright 6/29/2023
如果我错了,@isaactfa纠正我,但是一旦我放了一个泛型,一个实例只能容纳一种类型的闭包,对吧?TaskTask
1赞 isaactfa 6/29/2023
是的,没错。但 Chayim 的 HRTB 与终身省略实际上是一种巧妙的解决方法。
1赞 Jmb 6/29/2023
这可能是你想要的。

答:

3赞 Chayim Friedman 6/29/2023 #1

你想要的是更高等级的生命周期:

type AnyFuture<'a> = Pin<Box<dyn Future<Output = ()> + 'a>>;
type AnyClosure = Box<dyn for<'a> FnOnce(&'a mut Entity) -> AnyFuture<'a>>;

可以省略:

type AnyFuture<'a> = Pin<Box<dyn Future<Output = ()> + 'a>>;
type AnyClosure = Box<dyn FnOnce(&mut Entity) -> AnyFuture<'_>>;