如何存储和使用接受引用和 returns 未来的可选闭包?

How to store and use an optional closure that accepts a reference and returns a future?

我有一个异步函数 save,它有一个 Save 结构作为参数,它可以选择包含一个异步函数 (validator)。问题是以下代码仅在指定 Some(..) 时有效,而 None 编译器会抛出错误。

use std::future::Future;

trait SomeTrait {}

enum SomeError {}

#[derive(Debug)]
struct User {}

impl SomeTrait for User {}

struct Save<T, F>
where
    T: SomeTrait,
    F: Future<Output = Result<(), SomeError>>,
{
    pub validator: Option<Box<dyn Fn(&T) -> F>>,
}

async fn save<T, F>(obj: &T, args: Save<T, F>) -> Result<(), SomeError>
where
    T: SomeTrait,
    F: Future<Output = Result<(), SomeError>>,
{
    if let Some(v) = args.validator {
        (*v)(obj).await?;
    }
    Ok(())
}

#[tokio::test]
async fn test_func() {
    let user = User {};

    save(&user, Save { validator: None }).await;
    save(
        &user,
        Save {
            validator: Some(Box::new(|obj| async {
                println!("input: {:?}", obj);
                Ok(())
            })),
        },
    )
    .await;
}

错误:

error[E0698]: type inside `async` block must be known in this context
  --> test_utils/src/testin.rs:35:17
   |
35 |     save(&user, Save { validator: None }).await;
   |                 ^^^^ cannot infer type for type parameter `F` declared on the struct `Save`
   |
note: the type is part of the `async` block because of this `await`
  --> test_utils/src/testin.rs:35:5
   |
35 |     save(&user, Save { validator: None }).await;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

如何使上面的代码工作?有没有在 Save 结构中不使用 F 泛型参数的替代实现?我现在可以使用它,但当 Save 结构中有多个函数时可能会变得笨拙。

使用BoxFuture

既然要隐藏类型,那么使用trait对象就很有用了。 BoxFuture很适合这个,结合boxed方法创建:

use futures::{future::BoxFuture, FutureExt};
struct Save<T>
where
    T: SomeTrait,
{
    pub validator: Option<Box<dyn Fn(&T) -> BoxFuture<Result<(), SomeError>>>>,
}
let _ = save(
    &user,
    Save {
        validator: Some(Box::new(|obj| {
            async move {
                println!("input: {:?}", obj);
                Ok(())
            }
            .boxed()
        })),
    },
)
.await;

另请参阅:

将 None 与通用类型一起使用

这里的问题是泛型类型必须是已知的,即使您因为选择了 None 而没有使用它也是如此。您可以提供符合约束条件的类型(实现 FutureOutputResult<(), SomeError>)。这里我使用 Ready:

type Dummy = futures::future::Ready<Result<(), SomeError>>;

save::<_, Dummy>(&user, Save { validator: None }).await;

不幸的是,这会产生一个我还不知道如何解决的错误(“借用的数据不能存储在其闭包之外”)。

另请参阅: