所有权
所有权规则
- Rust 中的每一个值都有一个被称为其 所有者(owner)的变量
- 值在任一时刻有且只有一个所有者
- 当所有者(变量)离开作用域,这个值将被丢弃
变量作用域
- 作用域是一个项(item)在程序中有效的范围
- 变量在声明的那一刻开始直到当前作用域结束都是有效的
内存和分配
- 存放在堆上的变量
- 必须在运行时向内存分配器请求内存。
- 由变量声明的实现请求其所需的内存
- 需要一个当我们处理完 变量时将内存返回给分配器的方法
- 变量在拥有它的变量离开作用域后就被自动释放
- Rust 为我们调用一个特殊的函数。这个函数叫做 drop,在这里 String 的作者可以放置释放内存的代码。Rust 在结尾的 } 处自动调用 drop
变量和数据交换的方式
- 移动
- 浅拷贝 + 使原变量失效
- rust 永远也不会自动创建数据的 “深拷贝”。因此,任何自动的复制可以被认为对运行时性能影响较小
- 克隆
- 使用clone的通用函数
- 只存储在栈上的数据(Copy trait)
- 如果一个类型实现了 Copy trait,那么一个旧的变量在将其赋值给其他变量后仍然可用
- Rust 不允许自身或其任何部分实现了 Drop trait 的类型使用 Copy trait
所有权和函数
- 将值传递给函数在语义上与给变量赋值相似。向函数传递值可能会移动或者复制,就像赋值语句一样返回值与作用域
- 返回值可以转移所有权
- 可以使用元组返回多个值
引用(&)
- 允许你使用值,但是不获取所有权
- 可变引用(mut)
- 在同一时间,只能有一个对某一特定数据的可变引用
- 在任意给定时间,要么 只能有一个可变引用,要么 只能有多个不可变引用。
- 引用必须总是有效的
- 防止同一时间对同一数据进行多个可变引用的限制允许可变性,不过是以一种受限制的方式允许
- 避免数据竞争(类似于竞态条件)
- 两个或更多指针同时访问同一数据。
- 至少有一个指针被用来写入数据。
- 没有同步数据访问的机制
- 一个引用的作用域从声明的地方开始一直持续到最后一次使用为止
- 编译器在作用域结束之前判断不再使用的引用的能力被称为非词法作用域生命周期(Non-Lexical Lifetimes,简称 NLL)
借用
垂悬引用(垂悬指针)
- 在具有指针的语言中,很容易通过释放内存时保留指向它的指针而错误地生成一个 悬垂指针(是其指向的内存可能已经被分配给其它持有者)
- Rust 中编译器确保引用永远也不会变成悬垂状态:当你拥有一些数据的引用,编译器确保数据不会在其引用之前离开作用域
Slice
- slice允许你引用集合中一段连续的元素序列,而不用引用整个集合
- 可以使用一个由中括号中的 [starting_index..ending_index] 指定的 range 创建一个 slice
- starting_index 是 slice 的第一个位置,ending_index 则是 slice 最后一个位置的后一个值
- 在其内部,slice 的数据结构存储了 slice 的开始位置和长度,长度对应于 ending_index 减去 starting_index 的值
- Rust 的 .. range 语法,如果想要从索引 0 开始,可以不写两个点号之前的值
- slice 包含 String 的最后一个字节,也可以舍弃尾部的数字
- 也可以同时舍弃这两个值来获取整个字符串的 slice