类型生命周期边界的目的是什么?

3
fn foo<'a, T>()
where T : 'a 
{
   //code a
}

fn foo()
{
   //code b
}

在代码a中可以做什么,而在代码b中无法做到呢?

我希望它们是完全相同的,因为我不理解它们之间的区别以及生命周期限定的含义。如果有助于解释用例(例如参数),您可以建议对第一个函数进行补充。

3个回答

2
你可以在以下代码中看到需要使用bound(边界):
trait Elem {}

struct List<'a> {
    v: Vec<Box<dyn Elem + 'a>>,
}

impl<'a> List<'a> {
    fn push<T: Elem>(&mut self, t: T) {
        self.v.push(Box::new(t));
    }
}

error[E0309]: the parameter type `T` may not live long enough
 --> src/lib.rs:9:21
  |
9 |         self.v.push(Box::new(t));
  |                     ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
  |
help: consider adding an explicit lifetime bound...
  |
8 |     fn push<T: Elem + 'a>(&mut self, t: T) {
  |                     ++++

基本上,泛型类型可以具有任何生命周期,但有时您需要在只允许特定生命周期的上下文中使用泛型类型。在这种情况下,List<'a>只能包含至少与'a一样长的生命周期的元素。因此,T: 'a约束适用于这些情况。对于此语法,T: 'static是最常见的情况,表示该类型可能根本不包含任何局部引用。

所以这是针对Elem是任何引用类型的情况,对吗? - undefined
1
Elem是一个trait,因此底层类型可能是一个引用或者有引用,但也可能不是。 - undefined

1
通常情况下,当一个类型想要持有一个它不拥有的数据的引用时,它会被使用。
我认为Cow可能是一个很好的例子。
正如链接所示,它的完整签名是:
pub enum Cow<'a, B>
where
    B: 'a + ToOwned + ?Sized,
{
    Borrowed(&'a B),
    Owned(<B as ToOwned>::Owned),
}
lifetime参数允许结构体包含对B的引用,而无需拥有它。由于Cow不是B的所有者,借用检查器需要知道B的生命周期,以防止Cow持有的引用变得悬空。

移除生命周期限制不会引发编译错误。为什么会这样呢?有一件我很难理解的事情是,如果引用已经有了冗余的“a specifier”,为什么还需要它呢?例如,B是一个具有生命周期参数并持有引用的结构体-通过引用传递它会将其参数的生命周期绑定到引用的生命周期吗?还是这就是为什么我们明确地放置生命周期限制的原因? - undefined
2
是的,要小心。在这种情况下,B: 'a 实际上并不是必需的,因为它被 &'a B 隐含了。可以参考这个问答:Does &'a T imply T: 'a?。出于历史原因,它仍然存在。 - undefined

0
其他问题给出了需要明确界限的例子,但并没有完全回答问题。 fn foo1<'a, T: 'a>() {...}fn foo2<T>() {...}之间的区别在于,在foo1中,你能够给'a命名。在foo2中,你无法表达与T相关的显式生命周期界限。由于Rust可能会改变其他约束所暗示的隐式生命周期界限,因此受此约束限制的确切操作可能会随时间而变化。
例如,当你在代码中提及&'a T时,你隐含地意味着T: 'a。这以前是不成立的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接