Skip to main content

Command Palette

Search for a command to run...

Rust's lifetime

Published
2 min read

和其他语言不一样的,Rust 中的 lifetime 是可以显式定义出来帮助编译器进行判断的;为什么要显式的 Lifetime 呢?主要还是为了解决内存的引用的问题,其他的语言,尤其是 C++ 有大部分的问题都源于使用无效的内存或者已经释放的内存,这种情况在 C++ 语言中属于 undefine 的行为,所以就导致程序有的时候运行的好好的有的时候就发生莫名的错误,查类似的问题非常消耗时间和精力,而 Rust 就通过生命周期来彻底解决这个问题的。那么 C++ 没有这个概念吗?有,但是不强制,编译器也不检查。

Rust 中的生命周期和其他的语言一样,主要表示的当前变量能存活的时间范围;在 Rust 中每一个 borrow/ref 都会带上生命周期变量,为什么只是对 ref 强制呢,因为 ref 本质上是借用,而借用就可能会产生借用本身的生命周期大于 owner 本身,这就会导致内存问题,所以在 Rust 中所有的 reference 都是会有自己的 lifetime 的,但是很多时候编译器是会自动通过推导来计算出来的,所以我们看不到的,但是当编译器无法推断结果的时候就会报错,然后让程序员加入 lifetime 变量来帮助编译器推导。

1. 编译器推导三个准则

函数或者方法的参数的生命周期被成为输入生命周期,返回值的生命周期成为输出生命周期

  • 每一个引用参数都有它自己的生命周期参数,也就是如果一个函数或者方法有多个参数就有多个生命周期参数; fn foo<'a>(x: &'a i32) 一个生命周期参数,fn foo<'a, 'b>(x :&'a i32, c: &'b i32): 两个生命周期参数
  • 如果函数的参数只有一个 (一个输入参数),那么输出参数的生命周期都以输入参数的生命周期为准;
  • 如果是方法的话,所有的输出参数的周期以 self 的生命周期为准;

2. 使用

  • 最长的字符串长度
// 编译器会报错,说返回值缺少一个 lifetime,主要是因为编译器不知道返回值的 lifetime 是什么,按照上面三个规则,没有一个能命中,所以编译器报错的,于是程序员就需要来处理了
fn get_largest_str(left :&str, right :&str) -> &str {
    if left.len() > right.len() {
        left
    } else {
        right
    }
}

//定义一个生命周期的变量,'a,这个'a 是输入参数 left 和 right 中重叠的 lifetime,也就是这两个参数中最小的那个 lifetime
// 通过这么写之后编译器就知道将返回值赋值与一些变量的时候是否符合借用的要求;
fn get_largest_str<'a>(left :&'a str, right :&'a str) -> &'a str {
    if left.len() > right.len() {
        left
    } else {
        right
    }
}
  • struct 中使用借用变量

``` Rust implementation // 对于使用借用变量的结构体,必须指明 lifetime,因为只有这样才能让编译器发现结构体的生命周期和借用的生命周期,struct 变量绝对不能比借用的生命周期要长; struct RefStruct<'a> { part : &'a str, }

impl<'a> RefStruct<'a> { //不需要指明生命周期,原因是第三条规则; fn level(&self) -> i32 { 3 } }


* static 生命周期

`'static`表示其生命周期是存在于整个程序期间的;

``` Rust
let s :&'static str = "i have an apple";
  • 'static被用于 trait bound 的语意文档

在这种情况的 static 其实本质含义是:当前的参数是具有 ownership,而非 borrow,也就是说参数必须是具有 ownership 的,不能是借用的模式;

//表示 input 必须具有 ownership,不能是借用
fn print_it(input : impl std::fmt::Debug + 'static) {
    println!("{:?}", input);
}
#[test]
fn test_static() {
    let a = String::from("hello");
    print_it(a);

    let b = String::from("hello");
    print_it(&b); // error,编译器报错:** borrowed value does not live long enough **
}

3. 总结

从根本上来,为了能让编译器去帮我们判断程序中有哪些内存问题,编译器就必须知道一个变量引用另外的变量是否合法,这种合法性就需要通过 lifetime 来完成。编译器本身能自己完成一些,但是有一些必然是完成不了的,这个时候编译器就会求助与程序员,让程序员去加入更多的推测信息,通过这种强制语法来保证最后出来的程序是合法合规的,这种其实我能接受,而且我喜欢 Rust 的这种明确的感觉,什么的确都很明确,而不像 C++ 很多不明确的行为,需要程序员通过各种方式去规避,编译器没有尝试去帮助我们。

之前一直不明白为什么下面这个语句有问题?

let arr = vec![1];
thread::spawn(||{
    println!("{:?}", arr);
});

现在我明白了,对于 Rust 来说,lambda 本身默认使用的借用的方式去捕获变量,但是生成线程本身的 lifetime 可能是大于这个变量存在的 lifetime,所以必然会编译错误; 这也是 Rust 本身比较严谨的一个方面。

好了,lifetime 讲完了,其实这个东西不难理解,但是之前的语言并不会这么来用,所以做一篇笔记保留一下,后面的时候可以继续回顾。

More from this blog

Ai时代的工具链

本周是black Friday,我订阅了几个AI服务,还是蛮贵的...不过这样基本上构成我目前整体的知识阅读的过程,随着Ai的不断发展,工具链的替换可能是很重要的一个过程的。我主要订购了以下几个工具: Memo: 这个工具的主要作用是将视频/audio转srt,并且带有ai翻译的工具;当然我觉得它做的非常好的是,它把整个链路做的非常好的,并且可以用本地的资源做audio->text;而且它自带了很多的ai功能,比如对字幕进行进一步的AI的处理,提问,summarize和思维导图等等;目前我主要...

Nov 30, 20251 min read

做了一个噩梦

今天凌晨4点多起来看了一眼丈母娘的发烧是否ok...就导致我有点睡不着的,刷了一会推特之后又开始睡觉了,于是就开始做了一个很可怕的梦。 噩梦 那天,我不知道是在哪里..我带着女儿和我弟出去玩的,貌似是一个风景山区。于是我就带着女儿和弟弟出去玩的;我们走啊走, 沿着一条路一直走..突然看到一个小道有一家饭店的,这个饭店是比较特殊,有很多海鲜的;我看上了一只大龙虾,我问多少钱的,他说大概就70rmb就可以的。。。我觉得很划算的,我心想:我买下来,到时候把老婆叫过来一起吃的,并且告诉她这个才70rmb...

Nov 24, 20251 min read

子女教育-2

下面我分享一个推特上的一个关于子女教育的推 哈哈哈哈,李诞这个视频我看过 我给你分享几个我和我女儿之间的小故事 第一个故事 我经常给小朋友说:你们现在上学的成绩不重要,你们现在数学考试都是语文脑筋急转弯,语文考试都是历史背诵,一点用都没有,你出了社会就知道,社会根本没有选择题,社会要有选择题就好了,最难的是你遇到困难,你连门都找不到。我第一次这样讲的时候是女儿小学4年级,那时候我女儿听的一愣一愣的,她不明白,但是觉得我的理论和学校的不一样,很狂妄,但是她很喜欢,哈哈哈哈。 她什么时候真正明...

Nov 13, 20251 min read

被诈骗-马来西亚

最近我在国内,我老婆在马来;最近在计划搬家的,找的那个房子不包含一些必要的家具,于是我老婆就必须要买点家具的,主要是沙发和餐桌..我们本来计划是说去ikea去买,但是我老婆觉得ikea的家具不便宜,并且款式一般的,最终问了中介找了一个二手平台找找看不错的家具。 我老婆挑了两个家具的,我看了一下价格也不算便宜的,但是我老婆喜欢的,于是我就说你觉得ok那就购买吧。我还顺便问了一下,这个家具能不能线下看一下货的,但是我老婆说这货在很远的地方的,大概是300公里的一个城市的。那我就说这个包邮吗,我老婆说...

Nov 13, 20251 min read

当下和最近想做的事情

1. Current 当下 最近依然还在中国,已经回来快一个月了. 最近一直在忙着带丈母娘看病和住院的。索性一切都还在可控范围内的,丈母娘由于糖尿病控制的很差导致本身的冠心病也复发. 这次去浙江省人民医院去做了造影检查和支架植入的手术的,不过这一切都比我预估的要顺利,我就怕她由于长时间没吃药和高血糖的持续的时间太长了,会带来严重的问题,不过好在没有发生最坏的事情的。 因为做了手术,所以这段时间我和我老婆的姐姐每人轮换的陪床,不过陪床真的好累的,因为睡得很不好的,特别的累。不过好在都结束了,而且丈...

Nov 9, 20251 min read

Keep Move - 永不止步

39 posts