跳转到主要内容
Chinese, Simplified

好吧,距离我上次写已经有几个月了,但是时间过得真快🕊️
所以这是我在 Rust 进行微服务 Web 开发一年后的小日记,主要是一些想法的集合。


学习曲线


我有时听说使用 Rust 需要 1 个月才能获得生产力。
好吧,我不是计算机科学专业的毕业生(实际上我的专业更侧重于项目管理),但我仍然在这个领域工作了 13 年以上,对此我不太同意。 也许它对以前的系统程序员来说更容易,或者也许有些人比其他人学得更快。

仅作为一个比较:据我所知,JavaScript 花了我 1 个月的时间来适应,而在 6 个月内就可以高效地完成任何编码任务。


Rust 是……不同的。


而且我学习它的背景也不同:我以前也是唯一的 Rust 知识可以追溯到 2019 年初,当时我终于彻底阅读了 Rust 书。我非常简单地尝试设置对 websocket 的基本客户端请求。说我理解了那里的所有概念,或者说我在 2020 年记得它们,那将是一个公然的谎言。刚签下新合同,我应该接受 Rust 的培训。事实证明,就像经常发生的那样,我必须自己学习,同时仍然必须在截止日期内交付功能。谢天谢地,合理的那些给了我足够的时间来改进,但还不足以正确地阅读文档、观看学习资源、进行实验等等。大多数情况下,这必须在我的空闲时间完成,我做了很多。老实说,这是令人筋疲力尽的一年。


我想说的是,在第一个月之后,我能够编写 Rust 代码,而无需每隔 2 分钟左右就对编译器的错误感到惊讶。到那时我已经习惯了它们中的大多数,并且已经习惯了基础知识。熟悉编译器的错误是必要的:这意味着你了解编译器想要你做什么。
不知何故,漫长而广泛的特征仍然会让我目瞪口呆,例如这个:

 

那么这是什么?您可以将其称为另一种语言的“界面”。


它在这里描述了一个中间件,它将对其请求强制超时。


它接受一个通用请求,并将在将来的某个时间(也就是说,异步)返回一个通用响应或一个通用错误。


首先,这里有趣的是,只要此代码在范围内,此 Timeout 将自动为您的库、标准库或任何在 Rust 中创建或将要创建的库中的任何类型实现。


注意到这个淘气的 T::Error 了吗?它需要任何可以转换为指向动态大小错误的指针(其大小在编译时未知,基本上允许您自由传递任何类型的错误)装箱在堆上的某处(哦,这个指针也是顺便说一句,保证是非空的,但这是另一个话题)。这个“错误”对于线程之间的发送和同步(或共享,如果您愿意)也是安全的(以便运行时可以在多个线程上正确调度任务,如果认为合适的话)。两种响应变体都必须在内存中存在足够长的时间才能完成异步调用,这就是“静态”在这种情况下所表示的。
Rust 语言确实过于表达。


但是一旦你开始理解它,它就是美丽的。


3 个月后,我终于熟悉了它们,编写自定义实现有时很乏味,但最终还是完成了。


我也借此机会感谢整个 Rust 社区,尤其是 tokio 和 tonic 的贡献者和维护者。他们总是不遗余力地提供提示并善意地为我指明正确的方向。不管我的问题多么愚蠢,有时。


作为我自己故事的旁注,如果我可以说的话,Rust 有“很多方面”。其中之一是元编程,或称为宏。它基本上是允许您生成代码的代码。我很晚才开始和他们一起玩,主要是事先没有时间,并意识到它可以让我免去繁琐和耗时的样板。


这是一个指标,除其他外,我有时也“错误地学习”了 Rust,后来意识到它实际上可以更容易地完成。所以我对此的看法是:最好通过适当的时间和反思来学习 Rust。通常我不建议走和我一样的路,除非你喜欢挑战。


我想说的是,在那之后,大部分的实际学习都是生态系统本身。作为一种非常有表现力的语言,Rust crates 作者设计了使用他们的代码的“方法”,有时它会很自然,有时需要一段时间才能习惯它们。但是你对它们了解得越多,你就越能理解为什么它们是这样设计的。

时间已经过去了,我最终想分享的是,Rust 需要适当的时间、反思和思维方式的转变。 几个月前您甚至看不到一些深刻的好处,这绝对是正常的。 没有神奇的快进学习按钮。 对于经验丰富的开发人员来说,这甚至比新手更难,因为我们都从以前的语言(在我的例子中是 ActionScript、PHP、Java 和 JavaScript / TypeScript)中带来了以前的习惯。


但是,一个显着的区别在于可用的学习资源:至少可以说,当我开始时,教程和文档通常很少。 到目前为止,我看到越来越多的内容可供新手使用,更准确的文档和书籍,每周都会出现新的教程。
这是一件非常好的事情。


这值得你花时间吗?


剧透警报:确实如此😉
让我们看看为什么!

“I’m late! I’m late for a very important date! No time to say “Hello”, goodbye! I’m late, I’m late, I’m late!” ― White Rabbit

一次编写,到处构建⚙️

我们以前听说过,对吧?
但这一次也许是真的。


当然,我一开始一直在挣扎,有时我仍然在使用 Rust 时认知精疲力尽,但最后,它从未让我失望:超过编译器要求,在 Rust 中从来没有“你不能那样做”的时刻。
在您的这个特定用例中,生态系统可能还不成熟,它可能很难、压倒性或只是为时过早?当然。它需要你大量的阅读和实验吗?确实。
但最终一切都可以完成。
仅仅是因为 Rust 可以在各种平台上编译为本机代码,并且对 FFI 具有一流的支持,这意味着它可以与大多数语言(如果不是任何其他语言)对话。
我知道只要付出时间和精力,它就可以帮助我构建任何东西。


设置整个服务器基础架构?当然。
编写自定义 Flutter 插件、原生 Nodejs 模块或诸如此类的东西?是的。
甚至构建一个视频游戏、一个嵌入式设备......你的名字!
可能甚至建造一个连接到月球的烤面包机,谁知道呢。


编译时错误和安全☔

仅仅是因为,默认情况下,Rust 中根本不存在大量错误。
它的核心支柱之一是所有权和借用模型:编译器基本上会在任何时候强制您的变量被正确分配、在函数中传递、引用和使用。


它在细节上非常微妙,但本质上非常简单:您只能一次在一个地方改变一个变量,或者一次从多个地方读取,但永远不要同时做这两个。


因此,当变量超出范围时,可以自动释放内存,而无需垃圾收集器。
悬空指针、释放后使用、双释放、空指针异常等也一去不复返了。


在使用 Rust 一年多一点的时间里,我的 Web 服务几乎没有运行时错误。 很少有不同的,我可能可以用手指数数,认真的。
一旦编译,通常它就可以工作了™。


类似于 C 和 C++ ⚡ 的性能

Photo by Marc-Olivier Jodoin on Unsplash

简单地说:它快得离谱。
这意味着,例如,来自 Nodejs,在 Rust 中,即使我过度分配内存(克隆它直到你成功®)或编写优化不足的代码,它仍然平均比精心设计的速度快 5 到 20 倍 和优化的 JavaScript 代码。 为了降低内存消耗。


小轶事:我第一次查看数据反序列化吞吐量(使用 serde)时,我以为我在控制台输出中打错了,因为我的输入是一大块数据,结果显示在……以纳秒为单位。 我一遍又一遍地检查并运行它,直到我意识到一切都很好。 这就是它的速度。


“谁去那里? 是敌是友?” 问哨兵🎭

  • 照片由 @huanshi 在 Unsplash 上拍摄

和编译器?在最初的几周内会感到很烦人。
这绝对是几个月的障碍(我会说是对自己的生产力)。但最终成为某种最好的朋友。
编译器错误描述性过强,以至于它通常提供直接复制和粘贴解决方案,并附有解释。
每当我疲倦而遗漏某事或做事不当时:
编译器在那里努力提醒我。
同样由于 Rust 的严格性,我应该提到我现在花更多的时间编写断言实际业务逻辑的测试,而不是断言我对语言行为方式的假设的测试。

在其他语言中,作为开发人员,我们实际上自己持有不变量。必须记住这种方法在这种情况下不能正常工作,记住这种变量类型在与另一种类型相比时表现得非常狂野。在 Rust 中,一切都是无聊的类型。默认情况下,除了让它正确之外别无他法。
它勾起了你的好奇心?
看一看阿莫斯的这篇优秀文章以获得更深入的解释👇

混乱中的宁静🤸‍♂️

重构是一种幸福。 简直是小菜一碟🍰。
大多数时候它只是遵循编译器的指令。
由于大多数错误发生在 Rust 的编译时,因此一旦编译,任何东西都不太可能发生中断或倒退。


对于我使用过的其他语言,我不能完全肯定。 我什至知道我在说什么吗? 问问我以前的队友谁是“RefactoMan”。


没有工具的工匠什么都不是🧰

  • 谷仓图片在 Unsplash 上的照片

工具也是 Rust 感觉舒适、高效和实用的地方:例如,单元测试、文档生成、代码格式化程序和 linter 是内置的。
默认情况下它就在这里。


而且还有很多很多的工具可供使用。
举些例子:

  • - see generated assembly code for your program ? 👉 cargo-asm
  • - fuzz your tests ? 👉 cargo-fuzz
  • - timely compare 2 scripts execution ? 👉 hyperfine
  • - profile your code ? 👉 flamegraph
  • - enforce valid SQL queries at compile time ? 👉 sqlx
  • - enforce valid HTML template at compile time ? 👉 yarte
  • - use advanced tracing and telemetry ? 👉 opentelemetry

etc …


心态转变💭

 

不仅如此,我个人觉得今年我对计算机科学的了解比以往任何时候都多。 并不是特别是它以前不可用或记录不足。 它总是触手可及。 这只是因为,在大多数其他语言中,低级细节被抽象掉了,所以没有真正的动力去深入挖掘。
Rust 需要满足如此多的要求来编译代码的好处是它促使你修改你的基础知识。 美妙的V8黑盒不再处理事情了。
好吧,为了清楚起见,让我在这里重新表述一下:Rust 不会强迫你了解每一个潜在的细节,但它会让你非常了解它们。
此外,您将在 Rust 旅程中学到的有关内存安全的所有内容都与语言无关:因此它将对您之后使用的所有其他语言有用。


挑战极限⚗️

我特别喜欢的是 Rust 周围的热情。
许多人正在重新审视或创新以前很难用其他语言正确完成的领域,如果不是不可能的话。
鉴于编译器永远不会让你编译不是内存安全的代码,它提供了一个“安全网”上下文来试验疯狂的东西(尤其是多线程的)。


一个很好的例子是 rayon,这是一个 crate,它允许您通过简单地更改一行代码来并行化 CPU 密集型任务的迭代。


快速成长

想一想:


9 年前:由 Mozilla Research 孵化。
7 年前:它达到了第一个稳定版本。
4 年前:它正式开始支持 async-await 语法。
今天:它已经提供了成熟的生产就绪服务器解决方案。
好吧,我不了解你,但我不记得有一个编程语言生态系统发展得如此之快,除了当时的 JavaScript。
有趣的事实是,您实际上可能已经使用了一些,甚至没有意识到它。例如,您是否知道一些 Rust 已经进入:Dropbox、Figma、NPM、Microsoft、CloudFlare、Facebook、Amazon、Discord 和 Linux 内核?
生态系统仍有很多需要改进的地方:
本周 Rust 和 crates.io 是测量温度的好方法。
哦,还有一些网站跟踪它的演变,通常标记为:arewegameyet、areweguiyet、arewewebyet 等。
这可以很好地让您了解 Rust 是否已为您的下一个项目做好准备,或者需要一些额外的成熟度。


生产力🏃

所以一般来说,我将其总结为一个整体的方式:
值得花时间提前吗?
尤其是在最初的几个月里,在 Rust 中执行日常任务可能会花费通常执行它们的时间的三倍。随着一项改进,差距最终缩小了:例如,现在我可以像使用 Nodejs 一样快地使用 Rust 设置一个成熟的 REST API。只是花了更长的时间才到达那里。
它基本上是在编译时预先交易时间,
您最终会在运行时节省调试费用。
到目前为止,我个人更喜欢这种方法。


还记得那个导致你的脚本异常失败的小错误吗?还记得你花在调试上的时间吗?几天,几周?
问问自己,您是否愿意在前期投入更多时间。
这也是 Rust 的全部意义所在。


所以让我们总结一下我的收获


对于今天想开始 Rust 的人:

  • 不要急于求成:按照自己的节奏学习,适当的时间和反思。
  • 摒弃以前的习惯,避免系统地与其他语言进行比较:这需要转变思维方式。
  • 不要与编译器对抗:尽早接受它的建议。
  • 不要试图过早地进行过度优化:写一些先编译的东西,然后再提高它的效率。
  • 从小处着手,随着时间的推移而成长:找到您喜欢的主题的教程,这些教程可以让您快速入门,并在您的旅程中阅读 Rust 书籍。
  • 不要让你的生活变得复杂:a.k.a 在没有经验的情况下使用它来为一个期望很高但期限很短的客户使用它。
  • 玩得开心,实验!


结束语💬


既然你做到了最后,
谢谢你的时间,我希望你喜欢这个阅读🙂
我实际上有几篇关于实际 Rust 编程的文章,
我希望尽快交付。
直到下一次,大家保重!

原文:https://romain-kelifa.medium.com/after-one-year-of-rust-7cef608fef68

本文:https://jiagoushi.pro/node/2043

Article
知识星球
 
微信公众号
 
视频号