rust中的一些要点

lifetime消除规则

在rust中,每一个引用(reference)都拥有一个lifetime。rust对于安全性和编译时解决大部分问题的执着,要求我们在定义使用引用的函数或者结构体的时,需要指明引用的lifetime。在1.0版本之前,所有引用的lifetime都必须由开发者通过标注(annotation)的形式显式指定。之后,rust语言开发团队逐渐发现了一些可以预测lifetime的“套路”,并将其集成入后续版本中,使得rust程序员在很多情况下不需要为所有引用指定lifetime标注。 这些“套路”被总结为lifetime消除规则

在rust的函数定义中,参数和返回值的lifetime分别称为输入lifetime输出lifetime。如下3条规则中,规则1适配输入lifetime,规则2、3适配输出lifetime。如果rust编译器在尝试这3条规则后,仍然无法推断所有引用的lifetime,则会编译报错。

  1. 函数中每个参数都有相应独立的输入lifetime. 例如,fn foo<'a>(x: &'a i32)fn foo<'a, 'b>(x: &'a i32, y: &'b i32)

  2. 如果函数只有一个输入lifetime,'a,则所有返回值的输出lifetime都为'a。即fn foo<'a>(x: &'a i32) -> &'a i32

  3. 如果函数有多个输入lifetime,但其中一个是&self&mut self。即该函数是一个对象方法,则可以将self引用的lifetime赋给该方法的所有输出lifetime。

需要注意的是,上述lifetime消除规则,描述或者预测的其实是输入lifetime和输出lifetime的绑定关系。rust语言的特性要求在编译时刻,明确当前命名空间下所有引用的生命周期,以进行安全性检查,防止“野引用/指针(dangling references)”。但如果当前命名空间中有个发生了borrow行为的函数调用的返回值中又包含一个新的引用x,如何判定这个x的lifetime呢?

首先,rust要求引用不能比它指向的变量“活得更长”,因此这个返回的引用x的lifetime一定和输入lifetime有某种对应关系;

同时,出于编译器实现的可行性,我们不可能在编译时分析所有返回引用的函数定义,更不要说函数定义中可能包含多层调用嵌套……

所以,rust语言开发团队最后选择“尽人事,听天命”:适配了上述lifetime消除规则的,编译器可以在不分析函数定义,只查看函数声明的前提下推断输出lifetime;其他的漏网之鱼只能靠程序员拉编译器一把了……