为什么Rust函数的作用域比[duplicate]更一般

hrirmatl  于 2023-01-21  发布在  其他
关注(0)|答案(1)|浏览(92)
    • 此问题在此处已有答案**:

Calling a generic async function with a (mutably) borrowed argument(1个答案)
2天前关闭。
我试图将一个函数作为参数之一传递给另一个函数,但遇到了one type is more general than the other错误。
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e4074efd53fdf9e43d8f209405745dc0

use std::future::Future;

async fn constraint<A, Fut, L>(args: A, lambda: L)
where
    A: 'static + Send,
    Fut: Future<Output = ()> + 'static,
    L: Fn(&A) -> Fut + 'static,
{
    lambda(&args).await;
}

fn main() {
    constraint("hello".to_string(), lambda);
}

async fn lambda(_: &String) -> () {}

下面是错误消息:

error[E0308]: mismatched types
  --> src/main.rs:13:5
   |
13 |     constraint("hello".to_string(), lambda);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected trait `for<'a> <for<'a> fn(&'a String) -> impl Future<Output = ()> {lambda} as FnOnce<(&'a String,)>>`
              found trait `for<'a> <for<'a> fn(&'a String) -> impl Future<Output = ()> {lambda} as FnOnce<(&'a String,)>>`
note: the lifetime requirement is introduced here
  --> src/main.rs:7:18
   |
7  |     L: Fn(&A) -> Fut + 'static,
   |                  ^^^

For more information about this error, try `rustc --explain E0308`.

我不想改变lambda函数,因为我想在while循环中,用输入流中的第二个参数,多次调用它,但是我可以改变约束函数。
到目前为止,我试着给约束函数添加一个生存期,但我不确定这是否正确,因为A上应该已经有一个静态生存期:

async fn constraint<'a, A, Fut, L>(args: A, lambda: L)
where
    A: 'static + Send,
    Fut: Future<Output = ()> + 'static,
    L: Fn(&'a A) -> Fut + 'static,
{
    lambda(&args).await;
}

对应错误:

|
3  | async fn constraint<'a, A, Fut, L>(args: A, lambda: L)
   |                     -- lifetime `'a` defined here
...
9  |     lambda(&args).await;
   |     -------^^^^^-
   |     |      |
   |     |      borrowed value does not live long enough
   |     argument requires that `args` is borrowed for `'a`
10 | }
   | - `args` dropped here while still borrowed

还尝试移动参数,但得到相同的错误:

use std::future::Future;

async fn constraint<A, Fut, L>(args: A, lambda: L)
where
    A: 'static + Send,
    Fut: Future<Output = ()> + 'static,
    L: Fn(&A) -> Fut + 'static,
{
    async move {
        lambda(&args).await;
    };

}

fn main() {
    constraint("hello".to_string(), lambda);
}

async fn lambda(_: &String) -> () {}
mm5n2pyu

mm5n2pyu1#

这是因为lambdaimpl Future返回类型隐式地捕获了它的参数的生存期,但是constraint要求它是'staticFut: Future<Output = ()> + 'static
你的lambda可以反糖为如下形式:

fn lambda<'a>(_: &'a String) -> impl Future<Output = ()> + 'a {
    async {}
}

它的输出有一个生存期绑定到它的输入参数。
虽然constraint期望签名看起来像这样:

fn lambda<'a>(_: &'a String) -> impl Future<Output = ()> + 'static {
    async {}
}

您可以只使用最后一个定义(不需要显式生存期'a)。
我不确定是否以及如何使用async来表达这个意思

相关问题