Rust Learning

References

Web

LISP

  • Ketos is a Lisp dialect functional programming language.
  • Carp A statically typed lisp, without a GC, for real-time applications.

GUI

  • Are we GUI Yet? The state of building user interfaces in Rust.
  • conrod An easy-to-use, 2D GUI library written entirely in Rust.
  • druid Data-oriented Rust UI design toolkit.
  • libui-rs Rust bindings to the minimalist, native, cross-platform UI toolkit libui

Other

Learn web

“优于 std 的”工具箱

  • 在几乎所有方面,crossbeam 都比 std::sync::mpsc 更适合线程间通信,并且最终可能会合并到 std 中。
  • parking_lot 在几乎所有方面都具有优于 std::sync::Mutex 的 mutex 实现,并且某一天可能合并到标准库中。它还提供了其他许多有用的同步原语。
  • 与 Vec相比,bytes 是一种更健壮且通常性能更高的字节处理方式。
  • 如果你要进行底层网络优化,socket2 会是你的最终选项。

锦上添花

  • fern 是一种自定义和美化日志记录输出的简单方法。我们使用它来保持日志的可读性和内部标准化。
  • structopt 是你一直梦寐以求的 CLI 参数处理方式。除非你的依赖项几乎没有,否则没有理由不使用它。

Cargo 经典传奇

  • cargo-release 使我们能够轻松减少内部版本。
  • cargo-udeps 可以识别未使用的依赖项,并尽可能减少我们的构建时间。
  • cargo tree(最近集成进了 cargo)显示了一个依赖树,它在许多方面都很有用,但主要用于找出最小化依赖项的途径。
  • cargo-geiger 帮助我们快速评估外部依赖,以解决可能的安全性(或正确性)问题。
  • cargo-flamegraph 在跟踪代码中的性能热点时给了我们巨大的帮助。

持续测试

  • 我们使用谷歌的 Cloud Builder 来运行 CI 构建,因为我们的基础架构栈主要基于 GCP 构建,并且可以轻松调整构建机器规格和自定义构建映像。每次提交都会触发它,并运行 cargo clippy 和 cargo build。我们将 -D warnings 传递给编译器,以将警告升级为错误,确保我们的更改不会在可怜的同事下次拉取更改时劈头盖脸迎来大堆 rustc 警告。
  • 为了缩短配置项构建时间,我们将 target 和.cargo 目录缓存在 Cloud Storage 中,以便下次可以下载并增量构建。

国内镜像源

# 放到 `$HOME/.cargo/config` 文件中
[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"

# 替换成你偏好的镜像源
replace-with = 'sjtu'

# 清华大学
[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"

# 中国科学技术大学
[source.ustc]
registry = "git://mirrors.ustc.edu.cn/crates.io-index"

# 上海交通大学
[source.sjtu]
registry = "https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index"

# rustcc社区
[source.rustcc]
registry = "git://crates.rustcc.cn/crates.io-index"

Key points

  • 理解所有权:What is Ownership
    • Copy
    • Move
    • Clone
  • 理解引用和借用:References and Borrowing
    • & 引用
    • (&) 借用
      • We call having references as function parameters borrowing
      • 我们称“将引用作为函数参数”为“借用”
    • * 解引用

这里遇到一个实例:

use std::fs;

fn main() {
    println!("Start modifies");
    let paths = fs::read_dir("./").unwrap();

    let c = paths.count();
    println!("Count: {}", c);
}
// 这样就是 work 的
use std::fs;

fn main() {
    println!("Start modifies");
    let paths = fs::read_dir("./").unwrap();

    for path in paths {
        println!("Name: {}", path.unwrap().path().display())
    }
}
// 这样也是 work 的
use std::fs;

fn main() {
    println!("Start modifies");
    let paths = fs::read_dir("./").unwrap();

    for path in paths {
        println!("Name: {}", path.unwrap().path().display())
    }

    let c = paths.count();
    println!("Count: {}", c);
}
// 但是两个放一起就不 work 了,但我也不想再弄一个变量,于是就报错了。

结果找到原因是 Iterate 不同于数组容器只能使用一次,所以改为如下即可:

pub fn list_of_path(path: &str) -> vec::Vec<String> {
    let paths = fs::read_dir(path).unwrap();
    return paths.map(|path|{
        let name = path.unwrap().path().display().to_string();
        println!("Name: {}", name);
        return name;
    }).collect::<Vec<String>>();
}

let paths = list_of_path(S);
let c = paths.len();
assert_eq!(c, 7);
for p in paths {
    assert!(p.len() > 0);
    println!("Name: {}", p);
}

数据竞争

对于所有的类型T和任意的生命周期参数‘a,都能衍生出两种类型:&‘a T 和 &mut ‘a T。

&‘a T 相当于T的读取器,持有T的读锁, &mut ‘a T 相当于T的写入器,持有T的写锁。

编译器里有一个工具borrowck,在编译时会自动检查这两种类型的使用情况,如果有非法的使用,就报错,不让你编译通过。同样地,当你手中还持有着对一个值的引用时,编译器不允许将其移动或者销毁。这样,就杜绝了野指针现象和数据竞争问题。

let rb0 = &b;
let rb1 = &mut b;

值传递

Rust 的默认的值的传递是:转移。不管是赋值还是函数调用时的参数和返回值,都是这样。

分类体系(taxonomy)

开放的分类,使用泛型;封闭的分类,使用枚举(ADT)。

开放的全分类:Type + Trait