Rust part2


title:rust learning part2

Rust

第四章 所有权

所有权是Rust最独特的特性,他让rust不用GC就可以保证内存安全。

4.1.1 什么是所有权

  • Rust的核心特性就是所有权
  • 所有程序在运行时必须管理他们使用计算机内存的方式
    • 有一些语言有垃圾收集机制,在程序运行时,他们会不断地寻找不再使用的内存
    • 在其他语言中,程序员必须显示的分配和释放内存:如C,malloc以及free
  • 在rust中采用了第三种方式:
    • 内存是通过一个所有权系统来管理的,其中包含一组编译器在编译时检查的规则,并且不会产生任何开销,也就是说这一特性,并不会减慢程序的速度。
stack VS heap
  • stack 存储数据的方式是顺序的,并且遵循LIFO
  • 并且所有存储咋stack上面的数据必须拥有已知且固定的大小。
  • 也就是说,编译时大小未知的或者运行时可能发生改变的都应该放在heap上面。
  • 但是heap的内存组织性会差一些:
    • 当你把数据放入heap中时,你会申请一块足够大的空间,并标记为使用中,然后返回一个指针,作为这个空间的地址。
    • 这个过程叫在heap上进行的分配,简:”分配“。

这一部分知识与pwn基础知识大量重合,就不记录了。

主要就是,函数调用栈以及堆相关内容。

所有权存在的原因
  • 所有权解决的问题:
    • 跟踪代码哪些部分在使用heap 哪些数据
    • 最小化heap上面的重复数据
    • 清理heap上个面的未使用数据以避免空间不足

总之,管理heap数据才是所有权出现的原因

4.1.2 所有权规则

  • 每个值都只能有一个变量,这个变量是该值的所有者
  • 每个值同时只能有一个所有者
  • 当所有者超出作用域(scope)时,该值被删除。
变量作用域

注意变量的作用域仅仅只在声明变量之后到花括号结束点,这么一段范围。

String类型
  • string类型存储在heap上面
  • 字符串字面值:程序里面写死的字符串值,不可改变。
  • 能够在heap上面分配,能够存储在编译时未知数量的文本。
创建String类型的值

可以使用from函数从字符串字面值

image-20240110200025417

其中,”::“表示from时String类型下的关联函数;

并且这类字符串是可以修改的

  • 为什么String类型的值可以修改,而字符串字面值却不能修改?

因为他们之间处理内存的方式不同。

内存和分配
  • 字符串字面值,在编译时就知道它的内容了,其文本内容直接被硬编码到最终的可执行文件中,
    • 而其优点就是:速度快,高效。
  • String 类型,为支持可变性,需要在heap上面使用某种方式返回给操作系统
    • 这一步,在拥有Gc的语言之后,GC会跟踪并清理不再使用的内存
    • 如果没有GC,就需要我们去辨识内存何时不再使用,并调用代码将他返回。
  • RUST采用了不同的操作方式,当变量走出其作用范围后,就会收回他的内存。
变量和数据交互的方式:移动(MOVE)
  • 多个变量可以与同一个数据以一种独特的方式交互。

  • let x = 5;

    let y = x;

  • 整数时已知的且固定的大小简单的值,这两个5被压到了stack中。

但如果这里的类型是String类型

String类型
  • 一个String类型有3部分组成,一个 指向存放字符串内容的指针,一个 表示该字符串长度的值,一个 表示该字符串容量的值,而这些都存放在 Stack上面。内容则全部存放在,heap上面。
  • 而我们知道 在rust里面,如果一个变量走出了他的作用域,Rust就会调用一个Drop函数来释放他的内存,而这里我们就会遇到一个问题,如果let x = String::from(“hello”);let y = x;这里的y就会copy一份x的Stack上面的三个值,而不会copyheap上面的值,所以在同一个作用域中,就有了两个指向同一个区域的指针,在该作用域结束时,他们都会被回收,这也就代表着,这一块heap上面的区域,会被释放两次,也就会造成double free

这样肯定是不可以的,所以,Rust在这里引出了一个重要的概念 MOVE移动

也就是说当我进行如上的赋值操作后,x会直接失效,y会代替x存在,而当作用域结束后,x并不会释放,那一块heap区域,完全交由y来释放。

这里就要引出一个新的概念:

浅拷贝与深拷贝

我们一般认为,这样单纯复制指针,长度,容量的操作为浅拷贝,它不会复制实际的在heap上面的内容。

这里也隐含了一个RUst的设计原则:RUST不会自动的创建数据的深拷贝

  • 就运行是效率而言:任何赋值操作都是廉价的。

当然如果真的想对heaps上面的数据进行深度拷贝操作,而不仅仅是stack上面的数据,我们可以使用clone操作。

Stack上的copy(复制)

这里的复制操作,就是简单的操作,不存在浅拷贝和深拷贝。

  • Copy trait,可以用于像整数这样完全村存放在Stack上面的类型
  • 如果一个类型实现了Copy这个Trait,那么旧的变量再赋值后仍然可用
  • 如果一个类型或者该类型的一部分实现了Drop trait,那么Rust不允许让他再去实现Copy Trait
哪些类型可以实现copy trait
  • 所有标量的组合
  • 所有的整数类型
  • bool
  • char
  • 浮点类型
  • Tuple(所有字段值均可实现copy trait)

4.1.3 所有权与函数

  • 在语义上面将值传递给变量是类似的
    • 将值传递给函数将会发生移动或者复制
  • 注意,这里如果变量是上面几个说过的有copy trait的变量类型,那么他们就不会进行一个所有权的转移,仅仅只是一个浅拷贝,但如果是类似String类型的变量,那他在调用函数时,就会将所有权转移到被调用的函数中去。
返回值和作用域
  • 函数在返回值的过程中同样也会发生所有权的转移
  • 一个变量的所有权总是遵循着同样的模式:
    • 当一个值赋给其他变量时就会发生移动
    • 当一个包含heap数据的变量离开作用域时,他的值就会drop函数清理,除非数据被移动到另外一个变量中
如何让某个函数使用值,但不获得其所有权
  • 第一种方法就是,先将变量正常传入然后利用返回值的所有权传递,传回新变量手中,这样虽然变量名发生里改变,但是所有权没变,作用域也没变。

image-20240111212041346

  • 利用Rust的特性,“引用reference”。

4.2.1 引用与借用

引用
  • 参数的类型是&String 而不是String

  • & 符号就是引用:允许你引用某些值而不获得其所有权。

    image-20240111212611379

也就是说在引用时,回创建一个新变量内容是引用变量的指针。

借用

我们把引用作为函数的这个行为叫做借用

同样的借用是不可以修改原变量的,因为只是 借用

可变引用

将变量设为可变,参数可变,引用时可变即可。·

但是,可变引用有一个限制:在特定的作用域内,对某一块数据,只能有一个可变引用

这样做的好处是可以在编译时防止数据竞争。

  • 发生数据竞争的条件:
    • 两个或者多个指针同时访问一个数据
    • 至少有一个指针用于写入
    • 没有使用任何机制来同步对数据的访问

RUst在编译时就防止了这一种err发生

但是,我们只需要添加作用域即可

image-20240111213523993

可以看到这里我们只是添加了一对花括号而已,这样就完成了

第二个限制:不允许同时拥有可变引用和不可变引用:

image-20240111213751262

悬空引用(dangling references)
fn main(){
    let m = dangling();
}
fn dangling() -> &String{
    let note = String::from("helloe ");
    &note
}

报错:

image-20240111214207053

引用的规则
  • 一个可变引用或者任意数量的不可变引用
  • 引用必须一直有效

4.3 切片

m = dangling();
}
fn dangling() -> &String{
let note = String::from("helloe ");
&note
}




#### 引用的规则

* 一个可变引用或者任意数量的不可变引用
* 引用必须一直有效

   
  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值