当前位置: 首页 > news >正文

2024 Rust现代实用教程 Borrowing借用 Lifetime生命周期

文章目录

  • 一、Borrowing && Borrow Checker && Lifetime
    • 1.Borrowing
    • 2. Borrow Checker
    • 3.手动指定Lifetime
  • 二、Lifetime与函数
  • 1.任何引用都是有生命周期的
    • 2.生命周期与函数
  • 三、Lifetime与struct
  • 1.结构体中的引用
  • 参考

一、Borrowing && Borrow Checker && Lifetime

1.Borrowing

一个玩意两种描述
引用(Reference):

  • 1.引用是一种变量的别名,通过&符号来创建。(非所有权)
  • 2.引l用可以是不可变的(&T)或可变的(&mutT)。
  • 3.引用允许在不传递所有权的情况下访问数据,它们是安全且低开销的。

借用(Borrowing)

  • 1.借用是通过引l用(Reference)来借用(Borrow)数据,从而在一段时间内访问数据而不拥有它。
  • 2.借用分为可变借用和不可变借用。可变借用(&mut)允许修改数据,但在生命周期内只能有一个可变借用。不可变借用(&)允许多个同时存在。但不允许修改数据

2. Borrow Checker

·Borrow Checker的规则

1.不可变引用规则:
在任何给定的时间,要么有一个可变引用,要么有多个不可变引用,但不能同时存在可变引用和不可变引用。这确保了在同一时间只有一个地方对数据进行修改,或者有多个地方同时读取数据。

·2.可变引用规则:
在任何给定的时间,只能有一个可变引用来访问数据。这防止了并发修改相同数据的问题,从而防止数据竞争。生命周期规则:

3.引用的生命周期必须在被引用的数据有效的时间范围内。这防止了悬垂引用,即引用的数据已经被销毁,但引用仍然存在。

4.可变引用与不可变引用不互斥:
可以同时存在多个不可变引用,因为不可变引用不会修改数据,不会影响到其他引用。但不可变引用与可变引用之间是互斥的。

3.手动指定Lifetime

生命周期参数在函数/结构体签名中指定:

  • 一般情况下BorrowChecker会自行推断(随着Rust版本的更新,会越来越强)
  • 在函数/结构体签名中使用生命周期参数允许函数声明引用的有效范围。
fn main() {let mut s = String::from("Hello");// 不可变引用,可以同时有多个不可变引用let r1 = &s;let r2 = &s;println!("{} {}", r1, r2);let r3 = &mut s;println!("{}", r3);// println!("{} {}", r1, r2);//r1和r2已经失效了let result: &str;{// result = "ff";let r4 = &s;result = ff(r4);}// println!("r4 {}", r4);println!("{}", result);
}// 手动指定Lifetime
fn ff<'a>(s: &'a str) -> &'a str {s
}

编译及运行

 cargo runCompiling ch20_borrow_check v0.1.0 (/home/wangji/installer/rust/project/ch20_borrow_check)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.85sRunning `target/debug/ch20_borrow_check`
Hello Hello
Hello
Hello

二、Lifetime与函数

1.任何引用都是有生命周期的

大多数情况下,生命周期是隐式且被推断的
生命周期的主要目的是防止悬垂引用
关于“悬垂引用”的概念是指,引用指向的数据在代码结束后被释放,但引用仍然存在。

  • 生命周期的引入有助于确保引用的有效性,防止程序在运行时出现悬垂引用的情况。通过生命周期的推断,Rust 能够在编译时检查代码,确保引l用的有效性,而不是在运行时出现悬垂引用的错误。

2.生命周期与函数

编译器在没有显式注解的情况下,使用三个规则来推断这些生命周期:

  • 1.第一个规则是每个作为引用的参数都会得到它自己的生命周期参数。
  • 2.第二个规则是,如果只有一个输入生命周期参数,那么该生命周期将被分配给所有输出生命周期参数(该生命周期将分配给返回值)。
  • 3.第三个规则是,如果有多个输入生命周期参数,但其中一个是对self或不可变 self 的引l用时。因为在这种情况下它是一个方法,所以 self 的生命周期被分配给所有输出生命参数就是怎么标识这个生命周期

Example:

// 写法1
// 强制s1和s2的生命周期相同:'a就是个标识
fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {if s1.len() > s2.len() {s1} else {s2}
}// 写法2:性能好点,但是大多数时用不到
fn longest_str<'a, 'b, 'out>(s1: &'a str, s2: &'b str) -> &'out str
// 取出生命周期'a和'b的最大的
where'a: 'out,'b: 'out,
{if s1.len() > s2.len() {s1} else {s2}
}// 多个输入参数,需要指定生命周期
fn no_need(s: &'static str, s1: &str) -> &'static str {s
}
fn main() {println!("no need {}", no_need("hh", "ssss"));let s1 = "hello world";let s2 = "hello";println!("longest {}", longest(s1, s2));let result: &str;{let r2 = "world";result = longest_str(r2, s1);}println!("Longest string: {}", result);
}

编译及运行:

 cargo runCompiling ch21_func v0.1.0 (/home/wangji/installer/rust/project/ch21_func)
warning: unused variable: `s1`--> src/main.rs:26:29|
26 | fn no_need(s: &'static str, s1: &str) -> &'static str {|                             ^^ help: if this is intentional, prefix it with an underscore: `_s1`|= note: `#[warn(unused_variables)]` on by defaultwarning: `ch21_func` (bin "ch21_func") generated 1 warningFinished `dev` profile [unoptimized + debuginfo] target(s) in 0.19sRunning `target/debug/ch21_func`
no need hh
longest hello world
Longest string: hello world

三、Lifetime与struct

1.结构体中的引用

在结构体中的引用需要标注生命周期
结构体的方法(&self等)不需要标注生命周期

struct MyString<'a> {text: &'a str, // String,一般不要使用 &'a str
}impl<'a> MyString<'a> {fn get_length(&self) -> usize {self.text.len()}fn modify_data(&mut self) {self.text = "world";}
}struct StringHolder {data: String,
}impl StringHolder {fn get_length(&self) -> usize {return self.data.len();}fn get_reference<'a>(&'a self) -> &'a String {&self.data}fn get_ref(&self) -> &String {&self.data}
}fn main() {let str1 = String::from("value");let mut x = MyString {text: str1.as_str(), //String->&str};x.modify_data();println!("{}", x.text);let holder = StringHolder {data: String::from("Hello"),};println!("{}", holder.get_reference());println!("{}", holder.get_ref());println!("{}", holder.get_length());
}

编译及测试

 cargo runCompiling ch3_struct v0.1.0 (/home/wangji/installer/rust/project/ch22_struct)
warning: method `get_length` is never used--> src/main.rs:6:8|
5 | impl<'a> MyString<'a> {| --------------------- method in this implementation
6 |     fn get_length(&self) -> usize {|        ^^^^^^^^^^|= note: `#[warn(dead_code)]` on by defaultwarning: `ch3_struct` (bin "ch3_struct") generated 1 warningFinished `dev` profile [unoptimized + debuginfo] target(s) in 0.25sRunning `target/debug/ch3_struct`
world
Hello
Hello
5

参考

  • 2024 Rust现代实用教程

http://www.mrgr.cn/news/63535.html

相关文章:

  • Python 正则表达式完全指南
  • JavaEE之线程池
  • GaussDB分布式数据倾斜处理
  • 年度技术突破奖|中兴微电子引领汽车芯片新变革
  • ceph osd df 输出详解
  • 【JVM-2.1】如何使用JMC监控工具:详细步骤与实战指南
  • 【C++】关联式容器
  • [ 问题解决篇 ] win11中本地组策略编辑器gpedit.msc打不开(gpedit.msc缺失)
  • ElementUI中el-table双击单元格显示输入框
  • 提升安全上网体验:Windows 11 启用 DOH(阿里公共DNS)
  • 多SpringBoot项目同进程下统一启动
  • 华为认证HCIE通过需要考到多少分?_博睿谷·博睿慕课
  • layui 自定义验证单选框必填
  • Raspberry Pi 树莓派产品系列说明
  • Django入门教程——用户管理实现
  • 【C语言学习笔记】
  • 现货白银实时行情怎么看?首先搞清楚这个原则
  • @Async(“asyncTaskExecutor“) 注解介绍
  • 链栈的引用
  • C# 两个不同文件路径的同步
  • Latex中Reference的卷号加粗的问题
  • 指令系统 II(程序的机器级代码表示、CISC 和 RISC)
  • 写一个小日历
  • 中电金信:GienTech动态|丰收之秋,公司多项目获得荣誉
  • 如何解决docker镜像下载失败问题
  • (9)位运算