[易学易懂系列|rustlang语言|零基础|快速入门|(5)|生命周期Lifetime]

释放双眼,带上耳机,听听看~!

[易学易懂系列|rustlang语言|零基础|快速入门|(5)]

Lifetimes

我们继续谈谈生命周期(lifttime),我们还是拿代码来说话:



1
2
3
4
5
6
7
8
1fn main() {
2  let mut a = vec![1, 2, 3];
3  let b = &mut a;  //  &mut borrow of `a` starts here
4  // some code
5
6  println!("{:?}", a); // trying to access `a` as a shared borrow, so giving an error
7}                  //  &mut borrow of `a` ends here
8

我们在上篇文章说到,这段代码:



1
2
1println!("{:?}", a);
2

是过不了霸道的编译器女王的检查的?

为什么?

因为b借用了a的数据所有权,没有还回来。

所以,这时,访问a的数据时,编译器女王报错。

那要怎么办?加大括号 {}。

如下 :



1
2
3
4
5
6
7
8
9
10
1fn main() {
2  let mut a = vec![1, 2, 3];
3  {
4    let b = &mut a;  //  &mut borrow of `a` starts here
5    // any other code
6  }                  //  &mut borrow of `a` ends here
7
8  println!("{:?}", a); // allow borrowing `a` as a shared borrow
9}
10

我们可以看到,b 的“生命周期”,是限定在大括号 {}中的。

我们来看一个更清楚的代码:


[易学易懂系列|rustlang语言|零基础|快速入门|(5)|生命周期Lifetime]


我们现在知道,可以用大括号来限定变量或引用的生命周期。但太多大括号,会让你看得头大。

[易学易懂系列|rustlang语言|零基础|快速入门|(5)|生命周期Lifetime]

没关系,rust都为你考虑到了。下面是生命周期定义的标准写法。

翠花,上代码 :



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2// No inputs, return a reference
3fn function<'a>() -> &'a str {}
4
5// Single input
6fn function<'a>(x: &'a str) {}
7
8// Single input and output, both have the same lifetime
9// The output should live at least as long as input exists
10fn function<'a>(x: &'a str) -> &'a str {}
11
12// Multiple inputs, only one input and the output share same lifetime
13// The output should live at least as long as y exists
14fn function<'a>(x: i32, y: &'a str) -> &'a str {}
15
16// Multiple inputs, both inputs and the output share same lifetime
17// The output should live at least as long as x and y exist
18fn function<'a>(x: &'a str, y: &'a str) -> &'a str {}
19
20// Multiple inputs, inputs can have different lifetimes ?
21// The output should live at least as long as x exists
22fn function<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {}
23

我们可以看到,rust用'a 这样的注解来标注“生命周期”,即:单引号字符+小写字母。

如果有多个生命周期,就用字典顺序,如:'a 'b 'c 'd,v如此类推。

那从上面 的代码注释,我们也很清楚的明白,如果定义是同一种生命周期的注解的变量或引用,它们应该是相同生命周期,用人类的话来说:命一样长。

好理解。

上面的例子,是用在函数上,那其他类型呢?

我们来看看Struct 和Enum类型

请看下面代码:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1// Single element
2// Data of x should live at least as long as Struct exists
3struct Struct<'a> {
4    x: &'a str
5}
6
7// Multiple elements
8// Data of x and y should live at least as long as Struct exists
9struct Struct<'a> {
10    x: &'a str,
11    y: &'a str
12}
13
14
15// Variant with a single element
16// Data of the variant should live at least as long as Enum exists
17enum Enum<'a> {
18    Variant(&'a Type)
19}
20

我们看到,struct中的变量,定义为同一生命周期注解'a,则它们的“命一样长”。

也很好理解。

我们再看看接口实现和特征变量,如下 :



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1struct Struct<'a> {
2    x: &'a str
3}
4    impl<'a> Struct<'a> {
5        fn function<'a>(&self) -> &'a str {
6            self.x
7        }
8    }
9
10
11struct Struct<'a> {
12    x: &'a str,
13    y: &'a str
14}
15    impl<'a> Struct<'a> {
16        fn new(x: &'a str, y: &'a str) -> Struct<'a> { // No need to specify <'a> after new; impl already has it
17          Struct {
18              x : x,
19              y : y
20          }
21        }
22    }
23
24
25// ?
26impl<'a> Trait<'a> for Type
27impl<'a> Trait for Type<'a>
28

再看看泛型:



1
2
3
4
5
6
1// ?
2fn function<F>(f: F) where for<'a> F: FnOnce(&'a Type)
3struct Struct<F> where for<'a> F: FnOnce(&'a Type) { x: F }
4enum Enum<F> where for<'a> F: FnOnce(&'a Type) { Variant(F) }
5impl<F> Struct<F> where for<'a> F: FnOnce(&'a Type) { fn x(&self) -> &F { &self.x } }
6

有同学说,如果每次写函数定义,都要显式定义生命周期注解。那不是很麻烦的一件事。

没关系,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中的静态变量定义,它的生命周期是跟整个程序的生命周期一样,它一般用来定义全局变量。

如下:



1
2
3
4
5
6
7
8
9
10
1static N: i32 = 5; // A constant with &#x27;static lifetime
2
3let a = &quot;Hello, world.&quot;; // a: &amp;&#x27;static str
4
5
6fn index() -&gt; &amp;&#x27;static str { // No need to mention &lt;&#x27;static&gt; ; fn index ̶&lt;̶&#x27;̶s̶t̶a̶t̶i̶c̶&gt;̶
7    &quot;Hello, world!&quot;
8}
9
10


1
2
3
1如果遇到什么问题,欢迎加入:rust新手群,在这里我可以提供一些简单的帮助,加微信:360369487,注明:博客园+rust
2
3

这里简单总结一下这几个重要的概念:

1.在Rust,对数据或资源,Rust同一时间,只允许一个所有者。所有变量都是默认不可变的,数据一旦绑定到变量,这个变量就直接对这个数据拥有所有权(ownership),如果这个绑定变量,超出作用域(一般用大括号来限定),rustlang会自动释放这个变量和数据占用的内存,这就是Rust能做到内存安全的核心原理

2.如果,要再次绑定到另一个变量b,若数据是复制类型,数据会自动复制一份拷贝,再绑定到这个变量b上,所有权状态置为“ copied ”。若是借用类型,这个数据的所有权暂时借用给这个变量b,所有权状态置为“ moved ”。

3.资源(变量和数据)的生命周期,程序员自己控制,要保存资源的生命周期,在代码中其他调用它的时候有效(alive)。直到用完,并显示释放资源。

其实Rust的设计哲学,就是:

内存安全

零成本抽象

实用性

也就是说,Rust 语言中所有语法特性都围绕这三条哲学而设计,这也是 Rust 语言一致性的基础。

给TA打赏
共{{data.count}}人
人已打赏
安全技术

C++回调函数

2022-1-11 12:36:11

安全活动

求职大作战 人工智能将是第一大关卡

2016-12-18 5:19:30

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索