Rust简聊 - 所有权的使用方式

所有权

定义

  1. 所有权:指Rust数据的使用权
  2. 所有者:代码里就用变量表示
  3. 作用域:变量有效(valid)的那个代码区间。简单来说就是它定义时所在的那个最里层的花括号括起的部分,从变量创建时开始,到花括号结束的地方

解决问题

通过所有权系统管理内存数据,一方面有效解决数据的并发安全问题,同时编译器在编译时会根据一系列的规则进行检查,避免将错误带到程序运行时

规则

  1. Rust 中的每一个值都有一个 所有者owner)。
  2. 值在任一时刻有且只有一个所有者。
  3. 当所有者(变量)离开作用域,这个值将被丢弃 (所有权生命周期)

并不像 C 语言手动调用 free() 函数去释放堆中的资源

使用方式

rust 复制代码
fn main() {
    let s1 = "hello, world!".to_string();
    let s2 = s1;
    println!("{}", s2);
    println!("{}", s1);  //编译报错,
    //s1赋值后绑定了value的所有权, 将s1给s2赋值后,转移value的所有权给s2,s1将不再可访问
}

Rust 提供了两种权限转移方式,Move & Borrow 。比如租车,没有车的所有权,租来开几天总是可以的。租的行为不发生所有权转变,只是获取临时使用权,这种行为在 Rust 里叫 Borrow 。如果想拥有车的所有权,可以直接购买,买完 4S 店就没有车的所有权了,这种行为在 Rust 里叫 Move

语句 对应含义
let b = a; a绑定的资源转移给b,a不能再使用
let b = &a; a绑定的资源借用给b使用,b只有资源的读权限,a依然能再使用
let b = &mut a; a绑定的资源借用给b使用,b有资源读写权限,a依然能再使用
let mut b = &mut a; a绑定的资源借用给b使用,b有资源读写权限,a依然能再使用;同时b是可变的,可绑定到新的资源上面去

移动还是复制?

  1. 默认做复制所有权(copy)的操作的有 7 种。

    1. 所有的整数类型,比如 u32;
    2. 布尔类型 bool;
    3. 浮点数类型,比如 f32、f64;
    4. 字符类型 char;
    5. 由以上类型组成的元组类型 tuple,如(i32, i32, char);
    6. 由以上类型组成的数组类型 array,如 9; 100
    7. 不可变引用类型 &。(&mut 是不支持copy的,因为一个变量在一个时刻内只能有一个可变引用)。
  2. 其余的未实现copy trait的都是move

引用的分类

定义

  1. 不可变引用:&x是对变量 x 的不可变引用,不可以对值进行更改
  2. 可变引用:&mut x是对变量 x 的可变引用,可以对值进行更改

解决问题

  1. 不可变引用:是一种引用,为其他处理逻辑提供上文
  2. 可变引用:既是一种引用,又能够修改指向资源的内容

ex: 引用一个第三方库,它没有把所有权类型暴露出来,但是确实又有更新其内部状态的需求,就需要可变引用

引用生命周期

引用型变量的作用域是从它定义起到它最后一次使用时结束(肯定小于等于所有者的生命周期,否则容易产生悬垂指针)

引用生命周期的关键点

定义

简单说:多个只读引用&交叉无问题,多个可写引用&mut交叉有问题,一个可写引用&mut和一个可读引用&有问题,直接操作所有权的值 = 加一个可写引用

  1. 一个所有权型变量的可变引用 &mut 与不可变引用 & 的作用域不能交叠

    1. 报错:cannot borrow a as mutable because it is also borrowed as immutable

  2. 同一个所有权型变量的可变借用 &mut 之间的作用域也不能交叠

    1. 报错:cannot borrow a as mutable more than once at a time

  3. 在有引用 &/&mut 的情况下,不能对所有权变量进行写操作,只能借用完成(物归原主)才能更新

    1. 报错:cannot assign to a because it is borrowed

  4. 可以同时有多个可读引用 &****

ini 复制代码
fn main() {
  let mut a = 10u32; 
  let c = &a;       //变量c的生命周期由此开始
  let b = &mut a;   //变量b的生命周期由此开始
  *b = 20;          //变量b的生命周期到此结束
  println!("{c}");  //变量c的生命周期到此结束
}
//因此b和c的生命周期发生了交叉,所以发生了编译报错

解决问题

避免多线程条件下读写竞争导致的数据不一致性

相关推荐
Rust研习社12 小时前
组合真的优于继承吗?为什么 Rust 和 Go 都拥抱组合舍弃继承?
后端·rust·编程语言
红尘散仙2 天前
想写一个像样的终端 App?试试把 React 的开发体验搬进 Rust TUI
前端·rust
vivo互联网技术2 天前
从 Web 到桌面:基于 Tauri 2.0 + Vue 3 打造 vivo 线下门店「大头贴」拍照体验系统
前端·rust
Rust研习社2 天前
这 8 个 Rust 学习资源值得每个新手收藏起来
后端·rust·编程语言
星栈3 天前
10 分钟跑起第一个 Dioxus 应用:`dx` CLI、`rsx!` 和热更新好不好用
前端·rust·前端框架
望眼欲穿的程序猿3 天前
读取芯片内部温度传感器
嵌入式硬件·rust
望眼欲穿的程序猿3 天前
ADC 模拟电压采集
嵌入式硬件·rust
codexu_4612291873 天前
NoteGen 里一条记录如何变成 Markdown
前端·笔记·rust·tauri
Rust研习社3 天前
Rust 错误处理的黄金搭档:一个定义错误,一个传播错误
后端·rust·编程语言
techdashen3 天前
绕过系统 ICMP:用 rawsock、Npcap 和 WMI 找到默认网卡
开发语言·arm开发·rust