【问题标题】:What does a scoped lifetime in rust actually mean?rust 中的作用域生命周期实际上意味着什么?
【发布时间】:2014-03-05 03:45:41
【问题描述】:

所以,在:

fn v1<'a> (a:~[&'a str]) -> ~[&'a str] {
  return a;
}

#[test]
fn test_can_create_struct() {
  let x = v1("Hello World".split(' ').collect());
}

我知道,我读过http://static.rust-lang.org/doc/master/guide-lifetimes.html#named-lifetimes,但我不明白这段代码实际上做了什么

该函数基本上像通用 fn 一样参数化,但有生命周期,这是我在 IRC 频道上看到的,但让我们想象一下,我们有一个 L,它是一些特定的生命周期结构。

显然我是在暗示:

v1::<L>("Hello World".split(' ').collect());

..但我不是。传递给此函数的生命周期是生命周期的instance,它不是生命周期的 TYPE,因此该注释对我来说没有任何意义。

我的意思是,我基本上明白发生了什么(我认为):返回的~[&amp;str] 与调用者的作用域具有相同的生命周期,大概是test_can_create_struct() 函数。那是因为(据我了解)函数 v1 是在调用函数的生命周期 instance 中调用的。

非常混乱。

然后我们还有一些其他示例,例如: https://gist.github.com/bvssvni/8970459

这是一个片段:

impl<'a> Data<'a> {
  pub fn new() -> Data<'a> {
    Data { a: None, b: None }
  }

  pub fn a(&'a mut self, a: int) -> State<'a, Step1> {
    self.a = Some(a);
    State { data: self }
  }
}

现在我天真地假设Data&lt;'a&gt; 意味着函数a() 的生命周期实例是相同的。

即如果创建Datalet blah = Data::new())并调用blah.a(),则生命周期继承自create调用;即,只要父 Data 对象存在,返回的 State 对象就会存在。

...但显然这也是错误的。所以我现在根本不知道生命周期变量是什么意思。

救命!

【问题讨论】:

  • 生命周期类型系统的一部分;它们不是实例。

标签: rust lifetime


【解决方案1】:

因此,回答这个问题的最简单方法是退后一步,带您了解一生的真正含义。

让我们来一个简单的函数:

fn simple_function() {
  let a = MyFoo::new();
  println("{}", a);
}

在这个函数中,我们有一个变量a。这个变量和所有变量一样,存在一定的时间。在这种情况下,它一直存在到函数的末尾。当函数结束时,a 死掉。 a 的生命周期,可以描述为从函数的开头开始,到函数的结尾结束。

下一个函数不会编译:

fn broken_function() -> &MyFoo {
  let a = MyFoo::new();
  return &a;
}

当您使用&amp;a 时,您借用 引用a。然而,关于借贷的事情是,你应该把你借来的东西还给你。 Rust 对此非常严格,不会让您有无法返回的引用。如果您借用的参考资料已不在身边,则您无法归还参考资料,而那只是不在。

这对我们的broken_function 意味着,因为a 在函数末尾死亡,所以引用不能转义函数,因为这会使它比a 更持久。

下一步是这样的:

fn call_fn() {
  let a = MyFoo:new();
  {
    let a_ref = &a;
    let b = lifetimed(a_ref);

    println!("{}", *b);
  }
}

fn lifetimed<'a>(foo: &'a MyFoo) -> &'a MyBar {
   return foo.as_bar();
}

这里有两个函数,call_fnlifetimed,这里有一些微妙的东西,所以我会分解它。

call_fn 中,我首先创建MyFoo 的新实例并将其分配给a,然后,我借用a 的引用并将其分配给a_ref。借用的事情是,当您进行借用时,生命周期信息会从您借用的变量转移到引用本身。所以现在a_ref,作为一个变量,有自己的生命周期,在那个内部作用域的开始和结束处开始和结束,但是a_ref的类型有一个生命周期,那个从a转过来的。

具体的生命周期无法命名,但让我们假装我们可以通过使用数字来做到这一点。如果a 的生命周期是#1,那么a_ref类型&amp;'#1 MyFoo。当我们将a_ref 传递给lifetimed 时,编译器会像处理其他类型参数一样填写生命周期参数'alifetimed 的返回类型是具有相同生命周期的引用,因此编译器会填充那里的空间。有效地向lifetimed(foo: &amp;'#1 MyFoo) -&gt; &amp;'#1 MyBar 发出独特的呼叫。

这就是生命周期出现在类型参数列表中的原因,它们是类型系统的一部分,如果类型不匹配,那就是错误。编译器计算出函数编译所需的生命周期,因此您不必担心它,但不会在当前函数之外查看更多信息。您需要使用参数告诉编译器您正在调用的函数,以便它知道一切正常。


注意:您可以明确指定一个生命周期。 'static 这是在整个程序长度内持续的事物的生命周期。

【讨论】:

  • 非常感谢您的解释,但是,您能否举一些现实生活中的例子,当需要声明函数的生命周期时?我仍然无法捕捉到这个功能用例..
  • 我觉得泛型类型的使用很混乱。它实际上只是添加了一个标签来创建一个新的范围 /region ,泛型类型意味着为每个 'a , T 组合实例化一个新类型,例如 1 , T , 2,T 等,而 1,T != 2,T 是不是这样的。
猜你喜欢
  • 2012-01-26
  • 2020-02-15
  • 2016-10-09
  • 2018-11-11
  • 2017-06-03
  • 1970-01-01
  • 2020-11-30
  • 1970-01-01
  • 2019-06-02
相关资源
最近更新 更多