zoukankan      html  css  js  c++  java
  • Rust学习——所有权概念

    一、什么是所有权
    一旦理解了所有权,就不需要经常考虑栈和堆了。

    一些语言自带垃圾回收机制
    一些语言需要程序员手动分配内存和释放
    Rust通过所有权系统管理内存,编译器会在编译时根据一些列规则进行检查。在运行时,所有权系统不会减慢程序。

    栈(Stack):所有数据必须占用已知固定的大小
    堆(Heap):
    1. 大小未知或大小可能变化的数据存储在堆上
    2. 往堆放入数据时,需要请求一定大小的空间,内存分配器会在堆的某处找到一块足够的空位,标记为已使用,并返回一个表示该位置地址的指针,这个过程叫做分配(allocating)。

    入栈比堆分配快:因为入栈时分配器无需为存储新数据去搜索内存空间;且位置总是在栈顶。

    访问堆数据比访问栈慢:因为必须通过指针来访问。现代处理器在内存中跳转越少就越快。

    处理数据彼此较近建议用栈
    处理数据彼此较远建议用堆

    所有权系统解决的问题:
    1. 跟踪哪部分代码正在使用堆上数据
    2. 最大限度的减少堆上重复数据的数量
    3. 清理堆上不再使用的数据确保不会耗尽空间

    所有权规则:
    1. Rust中每一个值都有一个被称为其所有者(Owner)的变量
    2. 值在任一时刻有且只有一个所有者
    3. 当所有者(变量)离开作用域,这个值将被抛弃

    String类型:可变、可增长的文本片段,需要在堆上分配一块在编译时未知大小

    Rust中内存在拥有它的变量离开作用域后就被自动释放

    String 由三部分组成:一个指向存放字符串内容内存的指针,一个长度,和一个容量。这一组数据存储在栈上。右侧则是堆上存放内容的内存部分。

    变量与数据交互的方式(一):移动
    1. 二次释放问题。这个问题会导致内存污染。
    2. Rust 禁止你使用无效的引用。

    变量与数据交互的方式(二):克隆
    哪些类型实现了Copy trait ?
    - 所有整型:如u32、i32
    - 布尔类型
    * 所有浮点类型:如f64
    * 字符类型,char
    * 元组,tuple,当且仅当其包含类型也都实现Copy的时候

    所有权与函数
    Rust中,向函数传递值可能会移动或赋值,就像赋值语句一样。

    变量的所有权总是遵循相同的模式:
    将值赋给另一个变量时移动它。当持有堆中数据值的变量离开作用域时,其值将通过 drop 被清理掉,除非数据被移动为另一个变量所有。

    二、引用与借用
    引用:(无所有权)
    1. &符号,允许使用值但不获取其所有权
    2. 与使用&引用相反的操作时解引用,使用解引用运算符*

    借用:
    1. 引用的一个行为
    2. 在函数体里,被引用的变量无法修改自身引用的值

    可变引用
    1. 增加 &mut 标记引用即可改变引用的值
    2. 限制:在同一时间只能有一个对某一特定数据的可变引用。(同一时间只能可变引用一次)
    3. 上述限制的好处:在编译时避免数据竞争。
    4. 不能在拥有不可变引用的同时拥有可变引用

    非词法作用域生命周期(NLL):
    编译器在作用域结束之前判断不再使用的引用的能力。

    悬垂引用:
    指其指向的内存可能已经被分配给其他持有者

    警告:最好不要将变量的引用通过函数返回值的方式返回

    引用总结:
    1. 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用。
    2. 引用必须总是有效的。

    三、字符串Slices(无所有权)
    解决了什么问题?
    A:数据从某个特定状态计算而来的值,与该状态完全没有关联,导致不相关变量需要保持同步。

    let s = String::from("Hello");

    let slice = &s[0..2] // -> He
    // equally to
    let slice = &s[..2] // -> He
    let len = s.len();
    let slice = &s[3..len];
    // equally to
    let slice = &s[3..];

    字符串 Slice 类型声明标记:“&str”

    code eg:
    fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
    if item == b' ' {
    return &s[..i];
    }
    }
    &s[..]
    }

    fn main() {
    let mut input = String::from("Hello World");
    let word = first_word(&input); // 不可变引用
    println!("first word is: {}", &word);
    input.clear(); // 试图获取一个可变引用 input!
    println!("sec word is: {}", &word); // 此时又访问了不可变引用,导致可变与不可变引用同时存在,非法!
    }

    字符串字面值就是Slice类型
    1. 如:let s = "hello, world";
    2. 此处s类型是 &str,由于 &str 是一个不可变引用,所以字符串字面值是不可变的。

    其他类型的Slice
    数组类型也有slice,工作方式与字符串的一样,同时存储第一个集合元素的引用和一个集合的总长度。

    学习是一条令人时而喜极若狂、时而郁郁寡欢的道路。
  • 相关阅读:
    在线编辑器fckeditor的使用和配置
    Oracle CHAR,VARCHAR,VARCHAR2类型的区别与使用
    where having 的区别
    软件架构师之我见
    在线编辑器fckeditor的使用和配置
    where having 的区别
    必须掌握的八个【cmd 命令行】
    浅析PHP实现同步远程MysqlPHP编程教程详解
    MSSQL智能感应
    SQL统计表行数
  • 原文地址:https://www.cnblogs.com/tim100/p/15619629.html
Copyright © 2011-2022 走看看