如何在 Rust 中声明除生命周期之外的相同类型的泛型参数?

How to declare generic parameters of the same type except for lifetime in rust?

我写了下面的代码,但是我不能写生命时间约束来工作并得到一个错误:

use futures::Future;

async fn foo<'a>(a: &'a str) -> &'a str {
    let task = get();
    f(a, task).await
}

async fn f<T>(v: T, task: impl Future<Output = T>) -> T {
    if true {
        v
    } else {
        task.await
    }
}

async fn get() -> &'static str {
    "foo"
}

错误:

error[E0759]: `a` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
 --> src/lib.rs:3:18
  |
3 | async fn foo<'a>(a: &'a str) -> &'a str {
  |                  ^  ------- this data with lifetime `'a`...
  |                  |
  |                  ...is captured here...
4 |     let task = get();
5 |     f(a, task).await
  |     - ...and is required to live as long as `'static` here

playground

我觉得如果函数f中的两个参数可以有自己的生命周期就可以解决。 例如,

v: T,
task: S,
T: 'a,
S: 'b,
'b: 'a,
S == T

如何解决这个问题?

同样的问题可以用另一个最小的例子重现,使用函数接口而不是异步函数。

fn get() -> impl FnOnce() -> &'static str {
    || "foo"
}

fn foo<'a, T: 'a, F>(_: &'a str, _: F)
where
    F: Fn() -> T,
    T: FnOnce() -> &'a str,
{
}

let x = "".to_string();
foo(&*x, &get);
error[E0597]: `x` does not live long enough
  --> src/main.rs:22:11
   |
22 |     foo(&*x, &get);
   |     ------^-------
   |     |     |
   |     |     borrowed value does not live long enough
   |     argument requires that `x` is borrowed for `'static`
23 | }
   | - `x` dropped here while still borrowed

此示例允许我们将 get 转换为函数参数,并观察到传递此函数会对生命周期 'a 施加 硬约束 'static。尽管程序的初衷是好的,但返回供应商函数(或承诺)的函数不会提供关于输出生命周期的协方差。即() -> &'static str不满足for<'a> () -> &'a str。有时,编译器会退而求其次,建议您坚持使用最弱的 link,即 'static 生命周期,即使这可能并不理想。

请注意,目前表示在其生命周期内通用的类型的方法非常有限。这些是更高种类类型的一种形式,只能通过更高等级的特征边界指定某种级别的表达能力(以及最终的通用关联类型,一旦它们被完全实现和稳定)。在这种情况下,与其尝试让 f 为某种 T<'a>(伪代码)工作,不如让我们的 get 在整个生命周期内通用 'a.然后可以在实现中进行子类型化,因为我们知道字符串文字可以满足任何生命周期。

fn get<'a>() -> impl FnOnce() -> &'a str {
    || "foo"
}

async情况下(Playground):

async fn get<'a>() -> &'a str {
    "foo"
}

另请参阅: