首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >5/29 的 Rust 培训复盘及视频

5/29 的 Rust 培训复盘及视频

作者头像
tyrchen
发布2021-06-17 15:40:06
7930
发布2021-06-17 15:40:06
举报
文章被收录于专栏:程序人生程序人生

前几天一次突发奇想,促成了上周六的 Rust 培训。发帖的时候,觉得 Rust 还很小众,100 个名额绰绰有余,没想到报名非常踊跃,没多久就超过了六十。有些还一次性报了好几个人的名,然后微信发给我报名邮箱。我担心名额不够,连忙修改文章,把上限 100 人,改成了 75 人,省得超了。一顿操作之后,我觉得问题不大,就放心睡去。

谁料一觉醒来,报名人数已经多达 110,大大超过预期。既来之,则安之 —— 我为我的 zoom plan 上添了一个 large meeting pack —— 总不能让后来者吃亏吧。

由于想讲的内容很多,我把培训的长度定为四小时:我想塞进去足够丰富的内容,让 Rust 入门者除了了解 Rust 的能力外,还能学到品尝语言学习中不会触碰的东西。时间太短的话,意义不大,学不到太多东西;时间太长,我自己无所谓,反正有的是东西可以讲,但听众恐怕受不了。事实证明,我太高估我讲授内容的速度,四个小时的培训,我整整讲了五个小时。

我对于学东西和讲东西,喜欢走硬核道路和实用主义道路。其实一名优秀的开发者,只要对一门语言很硬核地掌握了,对各种基本概念知其然,也知其所以然,那么,学任何其他语言都会比较轻松。因为组成语言的要素是相同的,大家可以相互印证,融会贯通。比如传值和传引用是怎么运作的,数据分配在栈上和堆上都有什么不同,为什么有些东西要分配在栈上,有些只能分配在堆上,这些东西在一门语言身上学通了,另一门语言也是一样。所以我从一个值在一个 scope 下各种各样访问的方式讲起,从而推演出为什么所有权和借用规则要这么设计。

虽然,第一性原理大家都耳熟能详,唠个嗑还时不时能拿第一性原理出来凸显逼格,但有多少人在学习的时候会真正应用第一性原理呢?这就是硬核道路。

实用主义道路是所学的内容要和实际开发联系起来。大部分编程语言的教程,所给的例子是为了演示代码而演示,为了展示错误而展示,所以大多数时候,大家学完还会一知半解,且无法应用到自己的工作生活中。我能理解这些教程的无奈:几乎每本编程语言的入门都不得不假定学习对象没有太多基础,所以只好每个例子尽可能独立,简单,而并不关心其实用性。而我希望学习者能够直接在知识和实际使用中搭建起桥梁,这样,所解决的问题不是人造的问题,而是真实存在的场景。比如讲生命周期,我使用了 strtok 的例子。

所以在准备培训时,选取 live coding 的主题并不轻松:要保证硬核和实用性,例子还要足够容易理解。最终,我选择了这么几个例子:

  • value tour:基本上是 Rust 的 hello world,把一个值在 Rust 的体系下有哪些使用的方式过了一遍,即入门了 Rust 的基本语法,有了第一印象,又为所有权和借用检查做了一个铺垫。
  • 用文件持久化数据结构:内存中操作的对象最终都需要某种方式存储和发送出去,因而我们需要某种序列化机制和 IO 打交道。这个例子使用了 struct / enum 两种构造数据结构的方法,引入了 Write / Read trait,实现了 Default trait,使用了 std 里的文件 IO,也展示了在 Rust 下如何做 unit testing。
  • strtok:生命周期的展示。strtok 是所有 C/C++ 开发者都写过的入门例子,在 Rust 下,能简单写出并不容易。这是一个非常体现 Rust 内存管理范式转换思想的例子,过不了这关,就很难说对生命周期掌握得足够好。
  • 博物馆门票:本来是要撰写 RAII 相关的代码,结果发现似乎没有必要(Drop trait 仅仅打印了一下,没做任何和资源释放相关的事情),变成了展示 RAII 相关的代码。不过这是个不错的使用 Semaphore 的场景。
  • Fibonacci 遍历器:实现 Rust 的 Iterator trait。不难,但这个例子很有助于理解 Trait with associate type。
  • Event Encoder:泛型编程的例子。其实泛型写多了就不会感觉太困难,就像写函数一样,大家都是延迟绑定。只不过,撰写函数时,我们很明确这是提供给别人的 API,而撰写带泛型的数据结构时,这种感觉并不强烈。
  • Naive Actor:actor model 的 Rust 乞丐版实现。通过这个例子掌握 mpsc / oneshot channel,并且进一步夯实泛型编程。

从培训的过程看,这几个例子还是很不错地串起了相关的知识点。有小伙伴培训后跟我反馈「博物馆门票」的例子和 RAII 关系不大,我表示赞同;还有小伙伴觉得 Actor 的实现让他茅塞顿开,原来 actor 可以用 channel 这样巧妙地实现。不少小伙伴都希望,类似 actor 这样的例子能够更多。

培训中遇到的问题

这次培训,还是暴露出来一些我在准备方面的不足:

  1. 时间管理控制地不太好。一不小心超时了。超时的主要原因是 live coding,这个有些考验人,会出现一些预期之外的问题,现场解决略耗时。下次我会做更充足的准备。
  2. 培训到两小时左右时,我的耳机不争气地没电了。我的备用麦克风在楼下,还需要额外安装,就直接使用电脑的麦克风。结果很长一段时间我的声音都比较小,大家听起来比较费劲。
  3. 培训中进进出出的叮当声有些恼人,需要在 zoom 设置里关闭。
  4. 在回答 zoom chat 里大家提到的问题时,我没有读问题本身,这个对后来看视频的同学不够友好,不知道上下文。

培训视频

本次培训的视频已经稍作剪辑处理(主要是把中间那段声音小的部分处理了一下,视频加速 1.2 倍),放在 B 站和 Youtube 上。你可以在 B 站或者 Youtube 搜索「喜欢历史的程序君」找到我的频道,或者直接搜索题目「程序君的 Rust 培训」,就可以查看本期视频了。视频内容包括:

00:00 - Rust 初体验

15:20 - Live coding: Value tour

30:00 - 所有权和借用规则

40:55 - 类型系统初探

45:35 - 错误处理

48:25 - Live coding: 用文件持久化数据结构

01:15:25 - Rust 开发效率,ecosystem 和其他语言互操作

01:20:50 - 学 Rust 的方法

01:25:35 - 生命周期

01:42:50 - Live coding: strtok

01:53:00 - 静态生命周期

01:57:40 - RAII live coding: 博物馆门票

02:22:35 - 类型系统和泛型编程

02:33:30 - Live coding:Fibonacci 遍历器 02:40:05 - Trait Object

02:45:35 - Generics

02:53:12 - Live coding:Event Encoder

03:06:44 - 并发 - 并发原语

03:12:18 - Mutex 是如何构建的

03:18:55 - Semaphore 和 Channel

03:24:00 - Live coding: naive actor(实现一个简单的 actor model)

03:49:15 - 并发 - async/await

03:52:20 - Rust Future 原理

04:00:10 - 最后的 Q&A

第二期 Rust 培训什么时候弄?

第二期 Rust 培训,需要部分第一期 Rust 培训学到的基础知识(起码,内存管理,数据类型,泛型编程这些都不会详细讲了)。内容会包括:网络编程(设计中心化网络和 p2p 网络),宏编程,FFI 和 unsafe。也会是 4 小时左右的包含大量 live coding 的 Rust 培训。预计 6 月中下旬开讲。大家可以关注我的公众号文章。

贤者时刻

勘误:在讲 actor 例子之后的 Q&A,有小伙伴问道为什么 HandleCall trait 要实现在 Request 上,能不能实现在 Actor 上,因为他觉得实现在 Actor 上似乎更正确。我当时回答说也可以实现在 Actor 上。其实不对。按照我的做法:

pub struct Actor<State, Request, Reply> {
    receiver: mpsc::Receiver<ActorMessage<Request, Reply>>,
    state: State,
}

pub trait HandleCall {
    type State;
    type Reply;

    fn handle_call(&self, state: &mut Self::State) -> Result<Self::Reply, std::io::Error>;
}

Actor 是我定义的结构,HandleCall 是我定义的 trait,按照 coherence rule,只有我才能为 Actor 实现 HandleCall。这就失去其灵活性了。而 Request 是 actor 调用者可以决定的类型,所以对 Request 实现才足够灵活。当然,这就意味着,每一种 Request 需要实现一次 HandleCall。另一种做法是改变 HandleCall trait:

pub trait HandleCall {
    type Request;
    type Reply;

    fn handle_call(&mut self, request: Self::Request) -> Result<Self::Reply, std::io::Error>;
}

这样,可以在 actor 的 State 上实现 HandleCall。感觉这样更加贴合 erlang gen_server 的做法。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序人生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 培训中遇到的问题
  • 培训视频
  • 第二期 Rust 培训什么时候弄?
  • 贤者时刻
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档