张汉东 Rust 实战课

what is rust

modern c language with solutions to existed problems.

basic knowledge stage

compile

rustcode -> tokens -> AST -> HIR -> MIR -> LLVMIR -> machine code

const, const fn <—> MIRi (interpreter)

1
2
3
4
5
6
7
const fn answer() -> u32 { 42 }

const A: u32 = anwser();

fn main() {
  let _ = A;
}

数据类型

  • 基本数据类型
    • 数字 u8/f32
    • 数组 [T:n]
    • 字符 char
    • 字符串 str
      • 字面量
      • 动态可增长字符串
      • 从一段字符串中截取的片段
      • 字符串编码
      • FFI 中所需要转换字符串到 C 或 OS 本地字符串
      • 遵循特定格式的文件路径
    • slice [T]
    • pointer *const T
    • 引用 &T
      • 引用不可能为空
      • 拥有生命周期
      • 受借用检查器保护, 不会发生悬垂指针问题
    • 元组 (1,2,3)
    • Unit ()
    • Never !
    • 函数指针 fn
  • 自定义符合类型
    • struct
    • enum
    • union
    • 以枚举类型成员最大的对齐值为准, 不需要为每个枚举值都对齐
  • 容器类型
  • 泛型
  • 特定类型

Std Traits

  • Sync/Send
  • Sized
  • Default/Clone/Copy/Any
  • Display/ToString/Debug
  • PartialEq/Eq/Hash/PartialOrd/Ord
  • Add/AddAssign
  • FnOnce/FnMut/Fn
  • Deref/DerefMut/Index/IndexMut/Drop
  • From/Into
  • Error
  • TryFrom/TryInto/FromStr/AsRef/AsMut/Borrow/BorrowMut/ToOwned
  • Iterator/IntoIterator/FromIterator
  • Read/Write

函数与闭包

TODO: rewatch this chapter after understand ownership

 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
    fn foo<F: Fn() + Copy>(f: F) {
        f()
    }

    #[test]
    fn test_closure() {
        // FnOnce
        let c1 = || "c1";
        let c2 = || "c2";
        let v = [c1, c2];

        let i = 1;
        let c3 = || i;

        let mut j = 1i32;
        // FnMut
        let c4 = || {
            j = 3;
            j
        };

        // Fn
        let s = "hello".to_owned();
        let f = || {
            println!("{}", s);
        };

        foo(f);
    }

闭包

  • 未捕捉环境变量 - 所有权 ownership - FnOnce
  • 捕捉且修改环境变量 - 可变借用 &mut T - FnMut
  • 捕捉未修改环境变量 - 不可变借用 &T - Fn

闭包会自动实现部分 trait, 根据捕获的外界参数性质决定

  • Sized
  • Copy/Clone?
  • Sync/Send

模式匹配

  • let struct{x,y} = A
  • let Some(y) = Some(3)
  • match
  • if let
  • while let
  • for let

smart pointers

impl Deref/Drop

  • Box
1
2
3
4
5
fn main() {
  let x: Box<i32> = Box::new(32);
  let y = *x;
  assert_eq!(y, 32);
}

strings

  • unicode (u32)
  • 4 byte
  • convert to utf8
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
fn main() {
    let tao = '道';
    let _1 = tao as u32;
    assert_eq!(36947, _1);

    println!("U+{:x}", _1);
    println!("{}", tao.escape_unicode());

    assert_eq!(char::from(65), 'A');
    assert_eq!(std::char::from_u32(0x9053), Some('道'));
    assert_eq!(std::char::from_u32(36947), Some('道'));
    // not valid unicode
    // assert_eq!(std::char::from_u32(12909090909), None);
}

containers

Iter

for syntax sugar

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
fn main() {
    let v = vec![1, 2, 3, 4, 5];
    {
        // for scope
        let mut _itr = v.into_iter();
        loop {
            match _itr.next() {
                Some(i) => {
                    println!("{}", i)
                }
                None => break,
            }
        }
    }
}

module (crate)

  • package 是概念的包, 包含了单个或多个 crate
  • crate 是实际编译单元
  • codegen-unit - crate 默认会被按 LLVM IR 切割成 16 份
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
pub mod outer_mod {
    pub(self) fn outer_mod_fn() {}

    pub mod inner_mod {
        pub(in super::super::outer_mod) fn aaa() {}

        pub(crate) fn crate_visible_fn() {}
        pub(super) fn super_mod_visible_fn() {
            super::outer_mod_fn();
            inner_mod_visible_fn();
        }

        pub(self) fn inner_mod_visible_fn() {}
    }
}

action stage

ownership

let 绑定了变量与数据, 且指定了生命周期. let answer = 42;

  • move 动态增长类型
  • copy

  • 默认存储数据在栈上
  • 利用栈来自动管理堆内存

.

borrow check

thread & concurrent

the problem lock may bring

  • performance (context switch, thread wait)
  • dead lock

MESI (modified, exclusive, shared, invalid)

memory barrier (any operation before barrier happens before the operation after the barrier)

  • load (read) memory barrier
  • store (write) memory barrier
  • full

memory order

  • relaxed
  • release
  • acquire
  • acqrel
  • seqcst

trait

  • interface
  • mark
  • trait bound
  • trait object
    • std::raw::TraidObject
    • ObjectSafeValidation 需要满足对象安全限制
    • enum 妙用
    • Self::Sized

why Self::Sized?

  • Self: Sized 为了保证 trait 默认实现内部的 Self 调用都是合法的。
  • 防止函数体内包含了 Self 的默认实现混入虚表。因为虚表内 Self 无法确定。

error

  • assert!
  • Option
  • Result
  • panic
  • abort/unwind
 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
fn get_something(v: Option<&str>) -> &str {
  match v {
    Some(v) => v,
    None => "Not Found",
  }
}

use std::num::ParseIntError;

type ParseResult<T> = Result<T, ParseIntError>;

fn square(num_str: &str) -> ParseResult<i32> {
  num_str.parse::<i32>().map(|n| n.pow(2))
}

use std::panic;

#[test]
fn test() {
  let r1 = panic::catch_unwind(|| {println!("hello")});
  assert!(r1.is_ok());
  let r2 = panic::catch_unwind(||{panic!("err!")});
  assert!(r2.is_err());
  println!("finished test");
}

macro

any::TypeId 实现 class. Rust 应用每次启动, 都会给所有的类型生成不同的 typeId.

 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
use std::any::Any;

trait Foo: Any {
    fn as_any(&self) -> &Any;
}

impl<T: Any> Foo for T {
    fn as_any(&self) -> &Any {
        self
    }
}

struct Bar {}
struct Baz {}

impl PartialEq for Foo {
    fn eq(&self, other: &Foo) -> bool {
        let me = self.as_any();
        let you = other.as_any();
        if me.is::<Bar>() && you.is::<Bar>() {
            true
        } else if me.is::<Baz>() && you.is::<Baz>() {
            true
        } else {
            false
        }
    }
}

fn main() {
    let bar: Bar = Bar {};
    let baz: Baz = Baz {};
    let foo1: &Foo = &bar;
    let foo2: &Foo = &baz;
    println!("{:?}", foo1 == foo2);
}

declarative macros

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  macro_rules! unless {
      ($arg:expr, $branch:expr) => ( if !$arg { $branch };);
  }
  fn cmp(a: i32, b: i32) {
      unless!( a > b, {
          println!("{} < {}", a, b);
      });
  }
  fn main() {
      let (a, b) = (1, 2);
      cmp(a, b);
  }

derive proc macro

  • syn (syntax tree)
  • quote
  • proc-macro2 (token stream)

useful repo

unsafe

unsafe rust 不会提供安全检查的 五种操作

  • 解引用指针
  • 调用 unsafe 的函数
  • 访问或修改可变静态变量
  • 实现 unsafe trait
  • 读写 union 联合体中的字段

PhantomData 引入安全检查

https://blog.logrocket.com/unsafe-rust-how-and-when-not-to-use-it/

async

async io model

epoll

  • epoll_create(int size) 创建一个 epoll 数据结构, 返回一个 epfd
  • epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) 新增监听或取消监听事件, 也可进行修改
  • epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) 阻塞等待注册事件发生, 返回事件数量, 将触发的事件写入 events 数组

两种触发机制

  • LT 水平触发 - 缓冲区只要有数据就触发读写. epoll 默认工作模式
  • ET 边缘触发 - 缓冲区空或满的状态才会触发读写. nginx 使用该方式, 避免频繁读写.

async models

异步运行时由外界提供, Rust语言本身并不关心

others

  • future-rs
  • smol
  • async-std
  • tokio
  • rocket/actix-web/tower/hyper/warp

references

Get Things Done
Built with Hugo
Theme Stack designed by Jimmy