Rust language Intro

Rust

一门非常重视开发者用户体验的语言
如果你想从其他语言迁移到Rust,必须经过一段时期的思维转换(Paradigm Shift)

1
2
3
4
命令式(imperative)编程语言转换为函数式(function)编程语言
变量的可变性(mutable)迁移到不可变性(immutable)
弱类型语言迁移到强类型语言
从手工或者自动内存管理到通过生命周期来管理内存

Rust最大的思维转换就是变量的所有权和声明周期

1. 前置知识篇

  • 内存
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 栈
    > 栈自上而下增长
    > 栈是程序运行的基础,每当一个函数被调用时,一块连续的内存就会被栈顶分配出来,这块内存被称为帧(frame)
    > 在编译时,一切无法确定大小或者大小可以改变的数据,都无法放在栈上,只能放在堆上
    > 存放栈上的值,它的大小在编译期就需要确定

    # 堆
    > 堆自下而上增长
    > 堆上分配内存时,一般都会预留一些空间
    > 动态分配大小的内存需要被分配到堆上,动态声明周期的内存也需要分配到堆上.
    > 堆上分配出来的每一块内存需要显式地释放,这就使堆山内存有更加灵活的声明周期,可以在不同的调用栈之间共享数据
    > 堆可以存放大小未知或者动态伸缩的数据类型

    栈上存放的数据时静态的,静态大小,静态生命周期,堆上存放的数据时动态的,动态大小,动态生命周期

    # GC vs ARC
    1. GC在内存分配和释放上无需额外操作,而ARC添加了大量的额外代码处理引用计数,所以GC效率更高,吞吐量(throughput)更大
    2. GC释放内存的时机不确定,释放时引发的STW(Stop The World)会导致代码执行的延迟latency.一般携带GC的编程语言不适合做嵌入式系统或者实时系统
  • 数据
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    > 程序操作的对象

    # 值和类型
    > 编程语言的类型可以分为原生类型和组合类型
    - 原生类型(primitive type) : 所有原生类型的大小都是固定的,因此他们可以被分配到栈上
    - 字符
    - 整数
    - 浮点数
    - 布尔值
    - 数组array
    - 元组tuple
    - 指针
    - 胖指针(fat poiner): 比正常指针携带更多信息的指针
    - 组合类型(composite type) : 由一组原生类型和其它类型组合而成的类型
    - 结构体(structure type): 多个类型组合在一起共同表达一个值的复杂数据结构
    - 标签联合(tagged union): 不相交并集
  • 指针和引用
    1
    2
    指针和应用都指向内存地址,只不过二者在解引用时的行为不一样
    引用只能解引用到原来的数据类型
  • 函数
    1
    2
    3
    4
    > 函数时代码中重复行为的抽象
    > 方法时对象内部定义的函数
    > 函数是编程语言的基本要素,是对完成某个功能的一组相关语句和表达式的封装
    > 函数往往是一等公民,意味着函数可以作为参数传递,或者作为返回值返回,也可以作为符合类型中的一个组成部分
  • 闭包
    1
    2
    3
    > 闭包是一种特殊的函数,会捕获函数体内使用到的上下文中的自由变量,作为闭包成员的一部分
    > 闭包是将函数和其环境一起存储的一种数据结构
    > 闭包引用的上下文中的自由变量会被捕获到闭包的结构中,成为闭包类型的一部分
  • 接口&&虚表
    1
    2
    3
    4
    5
    # 接口
    > 作为一个抽象层,接口将使用方和实现方隔离开来,使两者不直接有依赖关系,大大提高了复用性和扩展性

    # 虚表 virtual table
    > 虚表是指向一张涵盖接口所支持方法的列表
  • 并发(concurreny)与并行(parallel)
    1
    2
    3
    4
    5
    6
    7
    # 并发
    > 并发是同时与多件事情打交道的能力,比如系统可以在任务1做到一定程度后,保存该任务的上下文,挂起并切换到任务2,然后过段时间在切换回任务1

    # 并行
    > 并行是同时处理多件事情的手段,任务1和任务2可以在同一个时间片下工作,无需上下文切换

    拥有高并发处理能力的编程语言会在用户程序中嵌入一个M:N的调度器,把M个并行任务,合理地分配在N个CPU core上并行运行,让程序的吞吐量达到最大
  • 同步和异步
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 同步
    > 指一个任务开始执行后,后续的操作回阻塞,直到这个任务结束
    > 同步执行保证了代码的因果关系(causality),是程序正确性的保证

    # 异步
    > 指一个任务开始执行后,与它没有因果关系的其他任务可以正常执行,不必等待前一个任务结束
    - Promise(future/delay/deferred): 对象用来描述未来某个时刻才能获得的结果的值
    - 初始状态: Promise还未运行
    - 等待pending状态: Promise已经运行,但还没有结束
    - 结束状态: promise成功解析出一个值,或者执行失败
    - async/await
    > async/await是一个语法糖(syntactic sugar)使用状态机将promise包装起来,让异步调用的使用感觉和同步调用非常类型
    - async定义一个可以并发执行的任务
    - await触发并发执行
  • 编程泛式
    1
    2
    3
    # 泛型编程
    - 数据结构的泛型
    - 代码的泛型化

2. 基础知识篇

  • 第一个程序
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    ➜ tree scrape_url
    scrape_url
    ├── Cargo.lock
    ├── Cargo.toml -- Rust项目的配置管理文件
    ├── src
    │   └── main.rs
    └── target
    ├── CACHEDIR.TAG
    └── debug
    ├── build
    ├── deps
    │   ├── libscrape_url-f8d1878e1d7fc033.rmeta
    │   └── scrape_url-f8d1878e1d7fc033.d
    ├── examples
    └── incremental
    └── scrape_url-2n1xt1o9t0ikb
    ├── s-g4eprmaq6h-ez2nl7-1g41whu33uaqz
    │   ├── dep-graph.bin
    │   ├── query-cache.bin
    │   └── work-products.bin
    └── s-g4eprmaq6h-ez2nl7.lock

    9 directories, 10 files

    scrape_url on  main [?] is 📦 v0.1.0 via 🦀 v1.52.0 took 8s
    ➜ cargo run
    Compiling scrape_url v0.1.0 (/Users/chyiyaqing/chyi/github.com/begin-rust/scrape_url)
    Finished dev [unoptimized + debuginfo] target(s) in 3.13s
    Running `target/debug/scrape_url`
    Fetching url: https://www.rust-lang.org/
    Converting html to markdown...
    Converted markdown has been saved in rust.md.

    > Rust使用cargo工具管理项目
    > Rust整体语法偏向C/C++风格
    > Rust支持面向接口编程和泛型编程
    > Rust有非常丰富的数据类型和强大的标准库
    > Rust有非常丰富的控制流程
    > Rust默认变量不可变,可以添加mut关键字让变量具备可变性
    > Rust项目的组织可以用mod来组织代码
    > Rust一个项目被称为crate (cargo new <name> -- lib 创建一个库)
  • Rust变量的所有权和生命周期
  • Rust内存管理方式
  • C的手工管理
  • Java的GC
  • Swift的ARC
  • Rust语言特性
    • 函数式编程特性
    • 类型系统
    • 范性编程
    • 错误处理

3. 进阶篇

*

4. 并发篇

  • 无畏并发(Fearless Concurrency)

5. 实战篇

  • HTTPie
    1
    > 

名词解释

学习过程就像《中庸》里谈治学的方法:博学之、审问之、慎思之、明辨之、笃(du)行之
算法+数据结构=程序, Pascal之父,图灵奖得主Niklaus Wirth

  • Paradigm Shift : 思维转换
  • Stack Overflow: 栈溢出
  • heap out of bounds: 堆越界
  • use after free : 堆上的内存被释放,但栈上指向堆上内存的响应指针没有被清空
  • Tracing GC : 追踪式垃圾回收(通过定期标记mark找出不再被引用的对象,然后将其清理sweep掉,来自动管理内存)
  • Automatic Reference Counting: 自动引用计数 (编译时,为每个函数插入retain/release语句来自动维护堆上对象的引用计数,当引用计数为零的时候,release语句就释放对象)
  • throughput: 吞吐量
  • syntactic sugar: 语法糖
  • Principle of Least Privilege: 最小权限原则
  • derive macro : 派生宏

阅读资料