如何在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

游乐场

我认为如果函数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。有时候,编译器会退回到建议您坚持最薄弱的环节,即'static生命周期,尽管这可能不是理想的。

请注意,目前表示泛型类型在其生命周期内的方法是相当有限的。这些是高级类型的一种形式,它们只能通过更高级别的trait边界指定某种程度的表达性(一旦它们被完全实现和稳定,最终是泛型关联类型)。在这种情况下,与其让f为一类T<'a>(伪代码)工作,不如让get'a的生命周期内泛型。然后,子类型可以在实现时进行,因为我们知道字符串字面值可以实现任何生命周期。

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

async的情况下(Playground):

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

参见:

  • 编译器建议我添加'静态生存期,因为参数类型可能不够长,但我不'认为'是我想要的
  • 这个实例怎么可能比它自己的参数寿命长?
  • 我们如何写一个通用函数来检查Serde序列化和反序列化?

最新更新