初学 Rust

早就想学 Rust 了但一直咕着这次小学期的程设训练开了 Rust 课堂就毫不犹豫地选了也以此为契机学了 Rust

这篇就是简单记录一下大体上的学习过程如果有什么心得体会经验分享之类应该会开新的文章

顺便也算是程设训练的游记了(游记这个词来源于 OI 时期的习惯

初学 —— The Rust Programming Language

不同于 PythonJavaScript这次学 Rust 更像是当初学 C++不是先魔改代码用啥搜啥StackOverflow而是在还没怎么接触过时就直接看书

虽然没有细看中文翻译的质量如何但至少术语是不好翻译的就直接看了英文版的 The Rust Programming Language

这本书看下来给我的感觉是很多地方没有按知识点依赖关系的拓扑排序来讲而似乎是以某种由浅入深的顺序来的很多后面才学到的概念在前文就出现而前面学的概念的完全不需要后面知识的扩展又在后面才补充还有一些零碎的知识是在 project chapter 讲的

反正每天看两三章还能有不少时间摸鱼摸个 一两周就看得差不多了

初步练习 —— 洛谷

看书的同时在 洛谷 上随便挑了点入门题和板子题写只不过一开始没学 io 之类的会再多语法也做不动题但幸好有 GitHub Copilot

在这放个读入的例子

6 0
1 1 4 5 1 4
fn main() {
    let stdin = std::io::stdin();
    let mut input = String::new();

    stdin.read_line(&mut input).unwrap();
    let mut parts = input.split_whitespace();
    let n = parts.next().unwrap().parse::<u32>().unwrap();
    assert_eq!(n, 6);
    let m = parts.next().unwrap().parse::<u32>().unwrap();
    assert_eq!(m, 0);

    input.clear();
    stdin.read_line(&mut input).unwrap();
    let a = input
        .split_whitespace()
        .map(|x| x.parse::<i32>().unwrap())
        .collect::<Vec<_>>();
    assert_eq!(a, vec![1, 1, 4, 5, 1, 4]);
}

复习 —— A half-hour to learn Rust

之前在 Hacker News 上看到了 A half-hour to learn Rust 这篇文章如果真的是看这个东西来学 Rust不说能不能学会肯定是学不扎实的但是看完书之后很多语法也忘了看这个用来复习还是非常不错的另外我感觉这个的顺序貌似比书更有条理一些虽然初学不一定友好 🤔

深入了解 —— The Rust Standard Library

其实看书的时候就感觉到了很多时候不懂一段代码不是不懂语法而是不懂 标准库 的实现而把 API 理解成了没学过的语法了解标准库不仅是提升编码和运行的效率也是能够看懂很多基础代码的关键

看文档的时候发现不仅是学到了很多有用的 methods也学到了很多其它东西比如说

  • 一般来说都可以用 std::cmp::max 来取 maxf32 专门有一个 pub fn max(self, other: f32) -> f32这是因为浮点数有 NaN 这个特殊情况导致 f32 没有 impl Ordstd::cmp::max 需要 Ord
  • 书里貌似没讲到的 keyword ref以及在 pattern matching 中和 & 的区别
  • 引用之间进行比较时会自动转成指向的值即实际进行比较的是指向的值可以通过 std::ptr::eq 来比较地址
  • 从标准库的 API 设计能领会到很多 trait 和 generic 的用法体会到它们组合在一起的强大
  • Iterator 自动有 IntoIterator所以用 IntoIterator 代替 Iterator 作为 trait bound 可以让函数更灵活
  • ……

简单看一看就能知道 the book 里涉及到的真的只是冰山一角学 Rust 标准库的意义会比学 C++ 的 STL 大得多个人感觉也可能是我 C++ 水平太低 / 没认真学 STL 😢或者 Primer Plus 讲的全一些

上课

Class 1

因为自学过了所以上课就基本上是把老师的声音当作 bgm 偶尔听一下然后继续看标准库文档

上课的时候老师提到 Rust 编译器可以提示如何修改于是我顺势在课程群里发了个 rust 程序员现状 的截图

rust程序员现状

课后把 OJ 上的作业速通后发现榜不是公开的 😢

后来还发现自己一道题写了个 collect 得到的 Vec 只用在一个 for就是说可以直接把迭代器用在 for 不用先 collect😵 想改过来但虽然没有公开榜还是不想承受可能的罚时

Class 2

第二节课前后共一天多的时间写了 16h 左右把 Wordle 大作业的基础功能写完了本来以为 Wordle 挺好写的没想到需求这么多需求文档模糊不清的地方还有的要问有的要自己设计

感觉课上讲的又快大作业需要的知识又没讲全很难想象如果不自学该怎么应对这个课

Class 3

修了一些文档说明不清导致的 bug然后研究了一下扩展功能怎么写

不知道为什么把单词按信息熵排序写了半天明明挺简单的可能是听着老师讲课没法专心想算法

后来试着用 rayon 把信息熵计算并行化了在我本机除了第一次猜测基本上都能秒出结果感觉很爽 甚至玩了半天意义不明的照着提示输入

再后来发现用 release 模式编译的优化比并行还大 🌚

第一次大作业验收

验收在 THUWC 去过的东主楼但上大学后还是第一次去结果走错了迟到了 5min 😵 然后非常慌张地展示提高功能都没太演示全感觉白写了

Class 4~8

第二次大作业验收

这次真的有比 pretests 强很多的 system test 了还好没 FST助教这个点你为什么能过啊x

可能是因为这个课不是学前端的而且助教只简单看了一下界面演示没看代码槽点很多的前端被夸了很科学

可能是因为这个课不是学数据库的而且听说有其他同学数据库里全是 JSON普普通通的建表被夸了很科学

关于课上的一些翻译

为什么什么都要翻译出来啊虽然如果英语母语的话看原文应该也很尬 🤣

trait: 特型;panic: 恐慌;poisoned: 中毒;crate: 箱;library crate: 库箱

大作业代码

听说可以把代码公开 加速熔断这就放上来

https://github.com/ouuan/course-assignments/tree/master/rust

Async Rust

先是看了 Asynchronous Programming in Rust感觉看得一知半解的尤其是 Pin好像大概知道 Future 在干什么又不完全知道而且这本书好咕啊TODO 的章节应该是有生之年了

没看完 async book直接去看 Tokio TutorialAsync programming in Rust with async-std作为 async runtime 的教程它们涉及到的具体原理和实现少一些更注重怎么实际使用读起来会容易理解一些因为 Tokio 更 popular主要看的是 Tokio 的教程

数据库: Diesel

感觉 diesel 的教程 写的挺简略的但对着 examples 硬查文档也勉强能看懂基本用法ORM 看着就很安全只不过实在是太类型体操了不仅文档查起来有点小麻烦代码复用也经常因为繁琐的 trait bounds 写不太动也可能是我没学会

diesel-derive-enum 是好用的

Sqlite 的 RETURNING 语句需要启用 returning_clauses_for_sqlite_3_35 feature flag并且需要至少 3.35 版本的 Sqlite没启用的时候对着一堆 trait bound 不满足的错误信息就和 C++ 模板感觉差不多了..根本发现不了错误原因还是翻文档翻半天发现的

还遇到一个 Sqlite 锁死的坑通过 使用 r2d2 设定 busy_timeout使用 WAL mode 以及 immediate transaction hopefully解决了