你所不了解的 Rust 生命周期

Rust - 生命周期

原文:https://hashrust.com/blog/lifetimes-in-rust/

译者:韩玄亮(一个热爱开源,喜欢 Rust 的 go开发者)

介绍

对于很多 Rust 的初学者来说,生命周期 (lifetime) 是一个很难掌握的概念。我也为此挣扎了一段时间,才开始明白它们对 Rust 编译器执行其职责 (move/borrow) 是多么重要。lifetime 本身并不难。只是它们是看似新颖的结构,以至大多数程序员都没在其他语言中见过它。更糟糕的是,人们过多地使用 “lifetime” 这个词来谈论很多密切相关的问题。在本文中,我将把这些想法分开,这样做是为了给你提供清晰地思考 lifetime 的工具。

目的

在讨论细节之前,让我们先了解一下为什么需要生命周期。它们的目的是什么?生命周期可以帮助编译器执行一个简单的规则: 任何引用本身都不能比它引用的对象存活地更久。换句话说,生命周期帮助编译器消除悬空指针错误(注:也就是说在引用的情况下才会出现生命周期标注)。

在下面的例子中你将看到,编译器通过分析相关变量的生命周期来实现这一点。如果引用的 lifetime小于被引用的 lifetime,编译成功,否则编译失败。

“lifetime”

生命周期如此令人困惑的部分原因是在 Rust 的大部分文章中,生命周期这个词被松散地用于指代三种不同的东西:

  • 变量的实际生命周期
  • 生命周期约束
  • 生命周期注释

下面让我们一个一个地来谈谈。

variables 生命周期

代码中变量之间的交互模式对它们的 lifetime 产生了一些限制。例如,在下面的代码中:x = &y; 这一行添加了一个约束,即:x 的 lifetime 应该包含在 y 的 lifetime 内 ( x ≤ y):

//error:`y` does not live long enough
{
let x: &Vec<i32>;
    {
				 let y =Vec::new();//----+
//                               | y's lifetime
//                               |
        x = &y;//----------------|--------------+
//                               |              |
    }// <------------------------+              | x's lifetime
    println!("x's length is {}", x.len());//    |
}// <-------------------------------------------+

如果没有添加这个约束,x 就会在 println! 代码块中访问无效的内存。因为 x 是对 y 的引用,它将在前一行被销毁。

需要注意的是:约束不会改变实际的生存期 —— 例如,x 的 lifetime 实际上仍然会扩展到外部块的末尾 —— lifetime 只是编译器用来禁止悬空引用的工具。在上面的例子中,实际的生存期不满足约束:x 的 lifetime 已经超出了 y 的 lifetime。因此,这段代码无法编译。

生命周期注释

如上一节所示,很多时候编译器会(自动)生成所有的 lifetime 约束。但是随着代码变得越来越复杂,编译器会要求开发者手动添加约束。程序员通过生命周期注释来实现这一点。例如,在下面的代码中,编译器需要知道 print_ret() 返回的引用是借用了 s1 还是 s2,所以编译器要求程序员显式地添加这个约束:

// error:missing lifetime specifier
// this function's return type contains a borrowed value,
// but the signature does not say whether it is borrowed from `s1` or `s2`
fn print_ret(s1: &str,s2: &str) -> &str{
    println!("s1 is {}", s1);
    s2
}
fn main() {
		let some_str:String= "Some string".to_string();
		let other_str:String= "Other string".to_string();
		let s1 = print_ret(&some_str, &other_str);
}

上一篇:麒麟服务器V10 SP1 安装httpd


下一篇:Mysql错误