Rust快速入门(五)

生命周期

生命周期的主要作用是避免悬垂引用。

这里我们详细说说借用检查:

rust 复制代码
{
    let r;                // ---------+-- 'a
                          //          |
    {                     //          |
        let x = 5;        // -+-- 'b  |
        r = &x;           //  |       |
    }                     // -+       |
                          //          |
    println!("r: {}", r); //          |
}                         // ---------+

rust使用了一个借用检查器来检查程序正确性,它会比较两个变量声明周期,比如上述代码中:r的生命周期是 'a ,x的生命周期是'b,由于a引用了b,由于b远远小于a,所以编译器会拒绝执行上述代码。

函数中的生命周期

rust 复制代码
fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";
​
    let result = longest(string1.as_str(), string2);
    println!("The longest string is {}", result);
}
​
fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

上述代码在rust中会报错,因为在longest函数中,编译器无法知道该函数的返回值到底引用 x 还是 y

也可以手动定义两个生命周期的长度规范:

rust 复制代码
impl<'a: 'b, 'b> ImportantExcerpt<'a> {
    fn announce_and_return_part(&'a self, announcement: &'b str) -> &'b str {
        println!("Attention please: {}", announcement);
        self.part
    }
}

上述<>内容表示 :

  • 'a 的生命周期至少和 'b 一样长

  • 'a 必须比 'b 活得更久或同样长

也可以这样做:

rust 复制代码
impl<'a> ImportantExcerpt<'a> {
    fn announce_and_return_part<'b>(&'a self, announcement: &'b str) -> &'b str
    where
        'a: 'b,
    {
        println!("Attention please: {}", announcement);
        self.part
    }
}

所以这里引出一个概念:在存在多个引用时,编译器有时会无法自动推导生命周期,此时就需要我们手动去标注,通过为参数标注合适的生命周期来帮助编译器进行借用检查的分析。

生命周期标注语法

生命周期标注并不会改变任何引用的实际作用域。标记生命周期只是为了取悦编译器,不让编译器为难我们。

生命周期的语法以' 开头:

rust 复制代码
&i32 // 普通引用
&'a i32 // 具有显示生命周期的引用
&'a mut i32 // 具有显示生命周期的可变引用

声明的规则:

  • 和泛型一样,使用生命周期参数,需要先声明 <'a>

  • xy 和返回值至少活得和 'a 一样久(因为返回值要么是 x,要么是 y

rust 复制代码
fn useless<'a>(x: &'a i32, y: &'a i32) -> &'a str {}

举一个例子:

rust 复制代码
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

上述代码中,返回值的生命周期与参数生命周期中的较小值一致,虽然两个参数的生命周期都是标注了 'a,但是实际上这两个参数的真实生命周期可能是不一样的(生命周期 'a 不代表生命周期等于 'a,而是大于等于 'a)。

函数的返回值如果是一个引用类型,那么它的生命周期只会来源于

  • 函数参数的生命周期

  • 函数体中某个新建引用的生命周期

结构体中的生命周期

与函数类似,不过多赘述

生命周期消除

对于编译器来说,每一个引用类型都有一个生命周期,编译器为了简化用户的使用,运用了生命周期消除大法

注意:

  • 消除规则不是万能的,若编译器不能确定某件事是正确时,会直接判为不正确,那么你还是需要手动标注生命周期

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

三条消除规则:

  • 每一个引用参数都会获得独自的生命周期

  • 若只有一个输入生命周期(函数参数中只有一个引用类型),那么该生命周期会被赋给所有的输出生命周期,也就是所有返回值的生命周期都等于该输入生命周期

  • 若存在多个输入生命周期,且其中一个是 &self&mut self,则 &self 的生命周期被赋给所有的输出生命周期

静态生命周期

'static,拥有该生命周期的引用可以和整个程序活得一样久。

返回值与错误处理

panic

复制代码
panic!()

panic时两种终止方式:栈展开直接终止

默认的方式就是 栈展开,这意味着 Rust 会回溯栈上数据和函数调用,因此也意味着更多的善后工作,好处是可以给出充分的报错信息和栈调用信息,便于事后的问题复盘。直接终止,顾名思义,不清理数据就直接退出程序,善后工作交与操作系统来负责。

线程panic如果不是main线程,那么程序就不会终止。

可恢复的错误Result

使用枚举Result:

rust 复制代码
enum Result<T, E> {
    Ok(T),
    Err(E),
}

实际例子:

rust 复制代码
use std::fs::File;
​
fn main() {
    let f = File::open("hello.txt");
​
    let f = match f {
        Ok(file) => file,
        Err(error) => {
            panic!("Problem opening the file: {:?}", error)
        },
    };
}

失败直接崩溃的 panic: unwrap 和 expect

如果返回成功,就将 Ok(T) 中的值取出来,如果失败,就直接 panic

rust 复制代码
use std::fs::File;
​
fn main() {
    let f = File::open("hello.txt").unwrap();
}
use std::fs::File;
​
fn main() {
    let f = File::open("hello.txt").expect("Failed to open hello.txt");
}

except相当于重载错误打印函数。

传播错误宏:?

rust 复制代码
use std::fs::File;
use std::io;
use std::io::Read;
​
fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("hello.txt")?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

它的作用跟 match 几乎一模一样

相关推荐
Wang's Blog5 分钟前
Java框架快速入门: Spring Security+OAuth2之邮件验证码发送(SMTP与API方式)
java·数据库·spring
“AI国潮设计-小江”16 分钟前
【Python/SDXL实战】潮汕国潮IP视觉落地:普宁英歌舞猫IP & 创意甜品设计(附ComfyUI工作流与商业授权说明)
开发语言·人工智能·python·prompt·aigc
529宝宝起名网25 分钟前
用 Python 分析汉字字源与起名用字的关联规律:从六书结构到文化寓意的起名偏好洞察
开发语言·python
linx29533 分钟前
单元九 · 零基础路线图-第 7–9 周·类与 RAII
c语言·开发语言·数据结构·c++·嵌入式硬件·算法
砚底藏山河1 小时前
容错重试与指数退避:网络抖动手抖不再丢数据(魔码量化实战 #04)
java·数据库·python·金融
白色的北极熊1 小时前
c语言 输出菱形字符串
c语言·开发语言
2501_930472442 小时前
云安全自查清单:用腾讯云助手 30 分钟完成一次权限与密钥体检
java·腾讯云
柯南46682 小时前
【AI开发之Rust】第 4 课:所有权系统 —— Rust 的灵魂
rust
学习智者2 小时前
《玄》IDE v3.6.3重磅发布:全功能修复与性能飞跃
开发语言·c++·ide·算法·中文语言 玄
guwentian2 小时前
Rolldown vs esbuild vs Webpack:Rust 打包器大战我们该怎么选
前端·webpack·rust·esbuild