【rust】| 06——语言特性 | 所有权

系列文章目录
【rust】| 00——开发环境搭建
【rust】| 01——编译并运行第一个rust程序
【rust】| 02——语法基础 | 变量(不可变?)和常量
【rust】| 03——语法基础 | 数据类型
【rust】| 04——语法基础 | 函数
【rust】| 05——语法基础 | 流程控制
【rust】| 06——语言特性 | 所有权

文章目录

  • 1. 所有权的概念
  • 2. 所有权的规则
  • 3. 变量的作用域
  • 4. 所有权的移动/克隆
    • 4.1 移动
    • 4.2 克隆 clone
    • 4.3 copy
  • 5. 所有权的转移
    • 5.1 函数转移
    • 5.2 返回值转移
  • 6. 引用和借用
    • 6.1 引用
    • 6.2 借用
    • 6.3 可变引用
    • 6.4 空引用
  • 7. 切片
    • 7.1 字符串切片
    • 7.2 其他切片
    • 7.3 切片的范围
    • 7.4 切片做函数参数

1. 所有权的概念

 所有权是Rust语言中一个关键的特性。它是一种内存管理规则(机制)。它通过这个规则(即所有权系统)结合编译器对代码进行检查 从而确保内存安全。
 在其他语言如C/C++ 等 都有自己的内存管理方式。C/C++需要我们显式(手动)处理所用的内存(申请、释放) 如果处理不当会造成很严重的内存安全问题。而Rust中这一特性很好的可以帮我们确保内存安全性。

2. 所有权的规则

1、每个值都对应一个变量 owner
2、一个值只能有一个 owner
3、有作用域,当owner超出作用域 值会被销毁 (这个变量有生命周期 在作用域内)

3. 变量的作用域

Rust中变量的作用域和其他语言类型。比如函数体内的 变量(局部变量) 它的作用域在 函数大括号之间 生命周期也是这么短。
【rust】| 06——语言特性 | 所有权_第1张图片
可以看到 超过范围销毁了。 对应所有权规则的最后一条。owner 就是这个值藏在暗处的变量名。 它超过变量作用域会消失。Rust内部在超出后 会掉清理函数 drop
清理变量占用的内存。

4. 所有权的移动/克隆

4.1 移动

Rust中的移动 类似浅拷贝 但有细节之处。
我们通过代码例子去理解

1、变量赋值操作

【rust】| 06——语言特性 | 所有权_第2张图片
分析:
  1、整型变量赋值 变量a 复制到了 变量b
  2、字符串赋值 变量s1 复制到了 变量s2
  我们可以看到 两种不同的类型 操作几乎是一样的。 整型它只是一个数字 再怎么复制占用的大小就那么多 无关紧要。可是当是一个很大的字符串 复制给另一个变量 那所占用的大小(很大*2) 这样的操作 太占用大小 咋的一个字符串准备要我命啊。是不是和其他语言复制操作很类似。
  但是在 Rust中 复制的操作 还是有细微差别的 我们深入了解下rust下 具体复制的具体过程

细看 字符串变量的定义及复制到其他变量的过程

【rust】| 06——语言特性 | 所有权_第3张图片
可以看到 字符串变量的内容 hello 存储在堆上 而 定义的变量 S1 只保存了 指向堆上内容的指针、长度和容量这三个 这些内容存储在栈上。并没有将 字符串内容也保存。
下面我们看 S1内容复制给S2 是怎样的
【rust】| 06——语言特性 | 所有权_第4张图片
可以看到 S1 复制到 S2 也只是复制了 指针、长度、容量三件套。不重复复制堆上内容。这样的情况下S1 S2是不是 占用栈大小很少。

如果S1 S2把数据一起保存呢
【rust】| 06——语言特性 | 所有权_第5张图片
可以看到 全保存过来 每个变量 都这样完全复制 那栈吃不消。当内容很大时 是不是 一个赋值操作直接给 栈空间 用完 干废掉啦。

通过上面图我们可以看到 rust中 变量保存了指向内容的指针等。 S1 和S2 中的指针都指向了 数据内容。我们知道所有权规则之一 变量超出作用域 会没了。那么当S1和S2 超出作用域 会尝试释放 因为它两指向一个地址那么 两次释放是不是会出大问题呢。也称为 双重释放错误。
当然 rust中也会想到这种错误 所以它会避免啦。
【rust】| 06——语言特性 | 所有权_第6张图片

【rust】| 06——语言特性 | 所有权_第7张图片
在Rust中 执行完 S2=S1这样的操作 S1已经变得无效啦 所以不会再存在上面双重释放的隐患了。
其实 Rust中S2 = S1 的操作类似浅拷贝 只拷贝了指针长度容量。但是rust 中超出范围 让其消失的规则 即S1 无效啦的操作 我们把这样称为 移动

4.2 克隆 clone

Rust中 我们把类似 深拷贝(把数据内容一起复制)的操作
称为克隆 clone。
【rust】| 06——语言特性 | 所有权_第8张图片

4.3 copy

前面学习完 移动和克隆 我们理解到 在Rust中 通过变量给变量赋值的操作 如果直接赋值 S2 = S1 这种 类似于浅拷贝 而且S1会消失 没有拷贝在堆上的内容 而 通过克隆 s2=s1.clone() 这种 类似深拷贝的操作 这样S1还活着。 下面我们通过例子理解COPY
【rust】| 06——语言特性 | 所有权_第9张图片
为什么x 还能用? 因为X是整型 编译器编译时 知道它的大小 将内容全部存储在栈中。也可以说整型具有copy特性 所以才会存在栈上。字符串型 大小我们不确定因为不知道后面会不会 改变。 在这种情况下 深浅拷贝(克隆)没区别。

具有copy特性的类型

  • 所以整型
  • 布尔类型
  • 所以浮点型
  • 字符型 char
  • 元组(元素类型为以上几种)

5. 所有权的转移

函数和返回值 都可以转移属性

5.1 函数转移

通过函数入参 将变量移动/复制 和变量移动/复制一样的
通过例子学习

【rust】| 06——语言特性 | 所有权_第10张图片
通过这个可以看到 和变量是一样的

5.2 返回值转移

通过返回值 转移

【rust】| 06——语言特性 | 所有权_第11张图片

6. 引用和借用

有些场景我们只需要使用值 而且会多次使用 一个变量本身具有所有权 多次使用需要移动来移动去 好麻烦 有没有办法不要所有权 那就是通过引用的方式。

6.1 引用

引用: 使用值而不转移(获取)所有权
引用没有所有权

引用通过地址来访问存储在该地址的数据

【rust】| 06——语言特性 | 所有权_第12张图片
【rust】| 06——语言特性 | 所有权_第13张图片
我们可以看到上面 函数定义入参 s: &sring 它的含义 我们创建了一个引用 来接收传入的实参引用 也称为 借用

6.2 借用

借用 是创建引用的动作
借用是 不能修改引用的值

借用 顾名思义 我借了别人东西 我要原模原样还给人家 不能说 搞坏了还吧
上demo
【rust】| 06——语言特性 | 所有权_第14张图片

可以看到 引用 和 默认情况下的变量 一样是不可变的

6.3 可变引用

引用默认情况下 不可修改内容 和默认变量一样

上面代码因为我们定义了不可变的变量等 那我们给他给加上可变的标志 是不是就可以变啦 是的

【rust】| 06——语言特性 | 所有权_第15张图片
可以看到 定义变量 函数入参等 都修改为 可变的 少一个都不行 否者会报错 既然要该那么都得是可变属性哦

可变引用的约束

1、一个变量只能有一个可变引用

防止多个引用同时对一个值 修改

【rust】| 06——语言特性 | 所有权_第16张图片

6.4 空引用

类似空指针。
在rust中 编译器会保证不会存在空引用。
编译器检测过程
【rust】| 06——语言特性 | 所有权_第17张图片
但我们又想用 函数内局部变量怎么办
前面我们学习了 返回值可以转移所有权 那么我们返回 变量是不是就可以了
【rust】| 06——语言特性 | 所有权_第18张图片

7. 切片

切片也是一种引用,切片没有所有权。
切片:对一个集合(元组 字符串) 引用其部分连续元素的操作
注: 切片不能对整个切 只能连续的某部分 是有范围的

7.1 字符串切片

【rust】| 06——语言特性 | 所有权_第19张图片
我们看看切片数据的内部存储结构是怎样的
【rust】| 06——语言特性 | 所有权_第20张图片
可以看到切片只存储了 起始位置的指针 和切的长度

还有一种字符串类型 &str 它指向二进制文件 这个字符串不可变
let s=“awdada”; // s是 &str类型

7.2 其他切片

和字符串切片类似 只是切的对象换了 可以切好多
比如 切数组 引用数组中一部分元素
【rust】| 06——语言特性 | 所有权_第21张图片

7.3 切片的范围

我们通过前面知道切片是如何创建
知道了 [ ] 方括号之间需要填切片的范围
那么当我们想切片的起始位置从0开始 除了 [0…x] 还有其他的表达方式

1、切片索引从0开始 的表达方式

【rust】| 06——语言特性 | 所有权_第22张图片

同样的 结尾位置 也可以 用省略 表达

2、切片索引 到末尾 的表达方式

【rust】| 06——语言特性 | 所有权_第23张图片

3、表示整个 同理 省略起始和结尾值 [ . . ]

7.4 切片做函数参数

【rust】| 06——语言特性 | 所有权_第24张图片

你可能感兴趣的:(编程语言,#,Rust,rust,开发语言)