【问题标题】:How to declare generic parameters of the same type except for lifetime in rust?如何在 rust 中声明除生命周期之外的相同类型的泛型参数?
【发布时间】:2023-03-29 22:25:01
【问题描述】:

我写了下面的代码,但是我不能写生命周期约束来工作并报错:

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 f&lt;'a, 'b: 'a, T&gt;(v: &amp;'a T, task: impl Future&lt;Output = &amp;'b T&gt;) -&gt; &amp;'a T?
  • 没有。 T 是一个包含生命周期参数的结构,例如 Cow&lt;'a, str&gt;。所以我不能将T 重写为&amp;'a T
  • 您的示例代码可以trivially be fixed by using a second type parameter U for the output type of the Future。您的示例代码没有说明为什么 TU 除了它们的生命周期之外需要是相同的类型。您的问题仅说明问题的尝试解决方案,而不是实际问题本身。很可能该解决方案没有声明两个除生命周期外相同的泛型类型参数,但如果没有更多信息,我们无法判断。
  • 谢谢。我修正了我的例子。我面临的真正问题更复杂,我不想在这里粘贴代码,因为我想展示 MVCE。
  • 我想知道为什么编译器会抱怨a 的生命周期必须是static,尽管T: 'a 是必需且足够的。

标签: rust lifetime


【解决方案1】:

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

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。尽管程序有最好的意图,但返回供应商函数(或承诺)的函数不会提供关于输出生命周期的协方差。也就是说,() -&gt; &amp;'static str 不满足for&lt;'a&gt; () -&gt; &amp;'a str。有时,编译器会回退到建议您坚持使用最薄弱的环节,即 'static 生命周期,即使这可能是不可取的。

请注意,目前表示在其生命周期内通用的类型的方法非常有限。这些是更高种类的类型的一种形式,只能通过更高等级的 trait bound(以及最终通用的关联类型,一旦它们完全实现和稳定)来指定某种程度的表现力。在这种情况下,与其试图让f 为一种T&lt;'a&gt;(伪代码)工作,不如让我们的get 在整个生命周期'a 中通用。子类型化可能会在实现时发生,因为我们知道字符串文字可以满足任何生命周期。

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

async 的情况下(Playground):

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

另见:

【讨论】:

猜你喜欢
  • 2019-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-21
  • 1970-01-01
  • 2021-05-24
  • 2016-12-02
  • 2020-01-04
相关资源
最近更新 更多