rust笔记11 生命周期&引用有效性

函数参数等的生命周期

rust保证内存安全的手段之一是没有悬空的引用(指针),而这个靠编译期间强制生命周期检查实现。先给出生命周期的声明方式:

&i32             // i32的引用
&'a i32          // 带有显式声明周期的引用
&'a mut i32      // 带有显式生命周期的可变引用

考虑函数一个函数(该函数不会通过编译):

fn longer(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

假设该函数能通过编译,而且在如下情景使用:

let x = String::from("foo");
let z;
{
	let y = String::from("hello world !");
	z = longer(x, y);
}
println!("{} is longer", z);

上述代码还会报错的,因为z的引用在离开作用域后,就失效了,println宏内部使用了一个悬空引用。

想要保证绝对内存安全,需要让返回的引用的有xy中最短的生命周期,给出实际的实现方式:

fn longer<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

这个声明,意味着返回的&strxy中最短的生命周期。这种的强制声明,可以检测出之前代码段的缺陷。

使用’a的方式,可以显式声明生命周期。生命周期语法是用于将函数的多个参数与其返回值的生命周期进行关联的。一旦他们形成了某种关联,Rust 就有了足够的信息来允许内存安全的操作并阻止会产生悬垂指针亦或是违反内存安全的行为。

结构体也可以采用类似的方式,代码实例:

struct Duck<'a, 'b, 'c> {
    name: &'a str,
    nick_name: &'b str,
    address: &'c str,
}

Duck结构实例化对象的生命周期一定是小于等于namenick_nameaddress中最小的那个。

省略生命周期

给出两个概念:

  • 输入生命周期:函数的输入
  • 输出生命周期:函数的返回值

三个省略规则:

  1. 每一个是引用的参数都有它自己的生命周期参数。换句话说就是,有一个引用参数的函数有一个生命周期参数:fn foo<'a>(x: &'a i32),有两个引用参数的函数有两个不同的生命周期参数,fn foo<'a, 'b>(x: &'a i32, y: &'b i32),依此类推
  2. 如果只有一个输入生命周期参数,那么它被赋予所有输出生命周期参数:fn foo<'a>(x: &'a i32) -> &'a i32
  3. 如果方法有多个输入生命周期参数,不过其中之一因为方法的缘故为 &self&mut self,那么 self 的生命周期被赋给所有输出生命周期参数。这使得方法更容易读写,因为只需更少的符号

直接给出代码实例:

fn print(s: &str); // elided
fn print<'a>(s: &'a str); // expanded

fn debug(lvl: u32, s: &str); // elided
fn debug<'a>(lvl: u32, s: &'a str); // expanded

// In the preceding example, `lvl` doesn’t need a lifetime because it’s not a
// reference (`&`). Only things relating to references (such as a `struct`
// which contains a reference) need lifetimes.

fn substr(s: &str, until: u32) -> &str; // elided
fn substr<'a>(s: &'a str, until: u32) -> &'a str; // expanded

fn get_str() -> &str; // ILLEGAL, no inputs

fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is ambiguous

fn get_mut(&mut self) -> &mut T; // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded

fn args<T: ToCStr>(&mut self, args: &[T]) -> &mut Command; // elided
fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command; // expanded

fn new(buf: &mut [u8]) -> BufWriter; // elided
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a>; // expanded

结构体的生命周期

如果结构体的生命周期与外界的相关联,那么结构体的方法也需要声明对应的生命周期,直接给出代码实例:

struct Duck<'a, 'b, 'c> {
    name: &'a str,
    nick_name: &'b str,
    address: &'c str,
}

impl<'a, 'b, 'c> Duck<'a, 'b, 'c> {
    fn foo(&self) {}
}

fn main() {}

静态生命周期

let s: &'static str = "I have a static lifetime.";

在整个程序中都是可用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值