# Lifetimes
我们继续谈谈生命周期(lifttime),我们还是拿代码来说话:
* * *
~~~rust
fn main() {
let mut a = vec![1, 2, 3];
let b = &mut a; // &mut borrow of `a` starts here
// some code
println!("{:?}", a); // trying to access `a` as a shared borrow, so giving an error
} // &mut borrow of `a` ends here
~~~
* * *
我们在上篇文章说到,这段代码:
* * *
~~~rust
println!("{:?}", a);
~~~
* * *
是过不了霸道的编译器女王的检查的?
为什么?
因为b借用了a的数据所有权,没有还回来。
所以,这时,访问a的数据时,编译器女王报错。
那要怎么办?加大括号 {}。
如下 :
* * *
~~~rust
fn main() {
let mut a = vec![1, 2, 3];
{
let b = &mut a; // &mut borrow of `a` starts here
// any other code
} // &mut borrow of `a` ends here
println!("{:?}", a); // allow borrowing `a` as a shared borrow
}
~~~
* * *
我们可以看到,b 的“生命周期”,是限定在大括号 {}中的。
我们来看一个更清楚的代码:
* * *
![](https://img2018.cnblogs.com/blog/544318/201912/544318-20191215184150344-428724045.png)
* * *
我们现在知道,可以用大括号来限定变量或引用的生命周期。但太多大括号,会让你看得头大。
![点击查看源网页](https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1574423633633&di=1bbe28b9d78f94cf7ce3b19ec25c950d&imgtype=0&src=http%3A%2F%2Fd.ifengimg.com%2Fmw604%2Fp2.ifengimg.com%2Fa%2F2017_11%2F86c2c1543960eb0_size20_w690_h690.jpg)
没关系,rust都为你考虑到了。下面是生命周期定义的标准写法。
翠花,上代码 :
* * *
~~~rust
// No inputs, return a reference
fn function<'a>() -> &'a str {}
// Single input
fn function<'a>(x: &'a str) {}
// Single input and output, both have the same lifetime
// The output should live at least as long as input exists
fn function<'a>(x: &'a str) -> &'a str {}
// Multiple inputs, only one input and the output share same lifetime
// The output should live at least as long as y exists
fn function<'a>(x: i32, y: &'a str) -> &'a str {}
// Multiple inputs, both inputs and the output share same lifetime
// The output should live at least as long as x and y exist
fn function<'a>(x: &'a str, y: &'a str) -> &'a str {}
// Multiple inputs, inputs can have different lifetimes 🔎
// The output should live at least as long as x exists
fn function<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {}
~~~
* * *
我们可以看到,rust用'a 这样的注解来标注“生命周期”,即:单引号字符+小写字母。
如果有多个生命周期,就用字典顺序,如:'a 'b 'c 'd,v如此类推。
那从上面 的代码注释,我们也很清楚的明白,如果定义是同一种生命周期的注解的变量或引用,它们应该是相同生命周期,用人类的话来说:命一样长。
好理解。
上面的例子,是用在函数上,那其他类型呢?
我们来看看Struct 和Enum类型
请看下面代码:
* * *
~~~rust
// Single element
// Data of x should live at least as long as Struct exists
struct Struct<'a> {
x: &'a str
}
// Multiple elements
// Data of x and y should live at least as long as Struct exists
struct Struct<'a> {
x: &'a str,
y: &'a str
}
// Variant with a single element
// Data of the variant should live at least as long as Enum exists
enum Enum<'a> {
Variant(&'a Type)
}
~~~
我们看到,struct中的变量,定义为同一生命周期注解'a,则它们的“命一样长”。
也很好理解。
我们再看看接口实现和特征变量,如下 :
* * *
~~~rust
struct Struct<'a> {
x: &'a str
}
impl<'a> Struct<'a> {
fn function<'a>(&self) -> &'a str {
self.x
}
}
struct Struct<'a> {
x: &'a str,
y: &'a str
}
impl<'a> Struct<'a> {
fn new(x: &'a str, y: &'a str) -> Struct<'a> { // No need to specify <'a> after new; impl already has it
Struct {
x : x,
y : y
}
}
}
// 🔎
impl<'a> Trait<'a> for Type
impl<'a> Trait for Type<'a>
~~~
再看看泛型:
* * *
~~~java
// 🔎
fn function<F>(f: F) where for<'a> F: FnOnce(&'a Type)
struct Struct<F> where for<'a> F: FnOnce(&'a Type) { x: F }
enum Enum<F> where for<'a> F: FnOnce(&'a Type) { Variant(F) }
impl<F> Struct<F> where for<'a> F: FnOnce(&'a Type) { fn x(&self) -> &F { &self.x } }
~~~
* * *
有同学说,如果每次写函数定义,都要显式定义生命周期注解。那不是很麻烦的一件事。
没关系,rust再次为你安排上了。
针对函数类型fn:
1.参数全部都是传递引用的函数可以直接这样定义:
`..(x: &str, y: &str)`
rust自动内部转化为:
`..<'a, 'b>(x: &'a str, y: &'b str)`
2.参数部分传递引用的函数可以直接这样定义:
`..(x: i32, y: &str) -> &str`
rust自动内部转化为:
`..<'a>(x: i32, y: &'a str) -> &'a str`
3.多个参数,有部分参数是&self或&mut self的传递引用函数:
`impl Impl{ fn function(&self, x: &str) -> &str {} }`
rust自动内部转化为:
`impl<'a> Impl<'a>{ fn function(&'a self, x: &'b str) -> &'a str {} }`
* * *
现在我们来看看静态生命周期注解:`'static`
其实,就是类似java中的静态变量定义,它的生命周期是跟整个程序的生命周期一样,它一般用来定义全局变量。
如下:
* * *
~~~rust
static N: i32 = 5; // A constant with 'static lifetime
let a = "Hello, world."; // a: &'static str
fn index() -> &'static str { // No need to mention <'static> ; fn index ̶<̶'̶s̶t̶a̶t̶i̶c̶>̶
"Hello, world!"
}
~~~
* * *
~~~
如果遇到什么问题,欢迎加入:rust新手群,在这里我可以提供一些简单的帮助,加微信:360369487,注明:博客园+rust
~~~
这里简单总结一下这几个重要的概念:
1.在Rust,对数据或资源,Rust同一时间,只允许一个所有者。所有变量都是**默认不可变**的,数据一旦绑定到变量,这个变量就直接对这个数据拥有所有权(ownership),如果这个绑定变量,超出作用域(一般用大括号来限定),rustlang会自动释放这个变量和数据占用的内存,这就是Rust能做到**内存安全的核心原理**。
2.如果,要再次绑定到另一个变量b,若数据是**复制类型**,数据会自动复制一份拷贝,再绑定到这个变量b上,所有权状态置为“**copied**”。若是借用类型,这个数据的所有权暂时借用给这个变量b,所有权状态置为“**moved**”。
3.资源(变量和数据)的生命周期,程序员自己控制,要保存资源的生命周期,在代码中其他调用它的时候有效(alive)。直到用完,并显示释放资源。
其实Rust的设计哲学,就是:
**内存安全**
**零成本抽象**
**实用性**
也就是说,Rust 语言中所有语法特性都围绕这三条哲学而设计,这也是 Rust 语言一致性的基础。
- rustlang语言零基础快速入门(1)开篇
- rustlang语言零基础快速入门(2)VSCODE配置
- rustlang语言零基础快速入门(3)所有权Ownership
- rustlang语言零基础快速入门(4)
- rustlang语言零基础快速入门(5)
- rustlang语言零基础快速入门(6)变量绑定
- rustlang语言零基础快速入门(7)函数Functions与闭包Closure
- rustlang语言零基础快速入门(8)Operators操作符
- rustlang语言零基础快速入门(9)Control Flows流程控制
- rustlang语言零基础快速入门(10)Vectors容器
- rustlang语言零基础快速入门(11)Structs结构体
- rustlang语言零基础快速入门(12)Enums枚举
- rustlang语言零基础快速入门(13)Generics泛型
- rustlang语言零基础快速入门(14)Impls & Traits实现与特征
- rustlang语言零基础快速入门(15)Unit Testing单元测试
- rustlang语言零基础快速入门(16)代码组织与模块化
- rustlang语言零基础快速入门(17)装箱crates
- rustlang语言零基础快速入门(18)use关键词
- rustlang语言零基础快速入门(19)多线程
- rustlang语言零基础快速入门(20)错误处理
- rustlang语言零基础快速入门(21)智能指针
- rustlang语言零基础快速入门(22)宏Macro
- rustlang语言零基础快速入门(23)实战1:猜数字游戏
- rustlang语言零基础快速入门(24)实战2:命令行工具minigrep(1)
- rustlang语言零基础快速入门(25)实战2:命令行工具minigrep(2)
- rustlang语言零基础快速入门(26)实战3:Http服务器
- rustlang语言零基础快速入门(26)实战3:Http服务器(多线程版本)
- rustlang语言零基础快速入门(27)实战4:从零实现BTC区块链
- rustlang语言零基础快速入门(28)实战5:实现BTC价格转换工具
- rustlang语言零基础快速入门(29)实战6:BDD工具cucumber_rust