这些情况会阻碍你学习Rust语言 - dystroy


我见过优秀的程序员努力学习 Rust,甚至放弃。我自己也遇到了一些困难。
以下是我所看到的可能导致您无法学习 Rust 的错误。我希望这份清单能帮助你避免它们。
 
错误一:没有准备好迈出第一步
学习 Rust 的最糟糕的方法是在完成繁重的工作后,在晚上的零星短时间里模糊地观察它,或者尝试一些小东西。当然,您之前确实学习过一些这样的语言,因此您可能对自己的能力充满信心。但是在 Rust 的某个时刻,它可能很快就会到来,你会遇到一个更高的步骤,如果你不以专注和奉献精神来对抗它,你就有可能无法克服它。
这可能令人沮丧。有些人放弃了。
如果你变得陈旧而你想走得更远,你应该

  1. 理解这很正常,因为 Rust 有不同的概念,你必须学习
  2. 不尝试就停止尝试,你是在浪费时间和动力
  3. 用专门的时间和精力回到战斗中

 
错误二:不看书就进入潜水
Rust 很大,并不是所有的事情都可以通过乱七八糟的方式变得显而易见。重要的是,您至少注意到了特征、宏、智能指针等,并且本书提供了对所有主要概念的简短介绍。
所以在你潜水之前,先对这本书(或几本书)有个大概的了解。也许没有完全阅读它,但请确保已阅读所有标题,以便您知道以后何时返回。
  
错误 3:从实施过时的技术解决方案(如算法和数据结构)开始
旧的 CS 课程充满了数学上漂亮的算法或数据结构,它们在白板或学习练习中反复使用。
最引人注目的例子是链表及其变体。
我总是看到新手来到 Stack Overflow 并询问如何编写它们。
这些结构是
  • 在最近的硬件中通常效率很低(并且大 O 表示法的指令数不会告诉你有多少)
  • 在 Rust 中很难做到

直接的简单答案是“在了解 Rust 之前不要尝试这些”。
稍后您可能会意识到您不需要它们,但与此同时,请相信使用链表学习 Rust 是一个非常糟糕的主意。
这是这篇著名的文章中首先观察到,链表仍然是新来者最喜欢沉船的暗礁之一。
  
错误 4:不阅读编译器错误
您可能习惯于编译器错误充其量只是指向您无法理解含义区域的模糊指针。
它在 Rust 中不起作用。Rust 的编译器是你最好的老师,他准确地解释了问题并提出了解决方案。
所以,我建议
  • 请注意您的 IDE 不会隐藏或截断编译器的输出
  • 注意编译器错误的准确措辞
  • 阅读建议

至少在开始时,查看错误的最佳方法是cargo check在您的控制台中运行。
 
错误 5:忽视编译器警告
你必须在两个时刻查看警告:
  • 当出现编译器错误而你不明白为什么
  • 当你的小任务完成并且没有错误时,在你提交甚至测试之前

已完成代码中的大多数警告实际上是错误。
 
错误 6:应用其他语言的最佳实践
在编写 Rust 时,使您成为其他语言的优秀程序员的大部分内容仍然有效,但在涉及简单的最佳实践时不要急于求成。它们可能无用、适得其反或在 Rust 中没有任何意义。
  • 尝试让 Rust 看起来像 OOP

当您不知道从哪里开始时,构建分层类树可能很诱人。您可能想说汽车显然是车辆,而卡车是汽车的一种,或者反过来说。
只是不要。不要寻找模拟继承的技巧。Rust 不是这样设计的,尝试使它成为 OOP 也无济于事。
  • 坚持让它发挥作用

你喜欢纯函数,对吧?副作用是你的克星,所以你要确保你只使用纯函数结构。
事实证明,函数式编程背后的一个动机问题在 Rust 中以另一种方式解决。
当我们说 Rust 的所有权模型确保内存安全时,人们通常认为这意味着不会有创建前使用或释放​​后使用或类似错误。它实际上更强大:对某些数据结构只有一个可变引用(即独占引用)意味着大多数数据不一致的来源也被删除。
因此,您可以在 Rust 中使用函数式风格,并且在 Rust 努力在编译时为抽象付费的意义上,它通常是低成本的,但是当它不起作用时,您不应该强迫自己坚持该风格。
在 Rust 中,当您的函数代码开始看起来难以破译并且编写起来很痛苦时,问问自己一个好的旧for循环是否会更好。
  • 构建不可变的结构和集合

直截了当地说,你不需要它们,再次感谢 Rust 的所有权模型。不放弃可变引用可以解决大多数问题。
  • 防御性编程

除了Option“十亿美元的错误”,Result而不是例外,以及 Rust 枚举的其他用途(允许您仅为相关变体设置字段),您在实践中几乎不会发现数据不一致的情况。
  • 使用虚拟值

没有那个必要。
旧代码:
let mut a = 0;
if some_expr() {
    a = some_fun();
} else {
    a = some_other_fun();
}

新代码:
let a = if some_expr() {
    some_fun()
} else {
    some_other_fun()
};

 
错误 7:构建生命周期重的 API
编写库很痛苦,因为我必须在任何地方都考虑生命周期。你不能只是摆脱它们。
当我设计我的第一个主要库Termimad 时,我希望能够以尽可能好的性能和尽可能少的内存成本使用它。在库的第一个版本中(更具体地说是我并行开发的 Minimad 依赖项),String这个文本操作箱的任何结构中都没有。我只使用引用,到处都是引用。
第一个问题是直接的:编写库很痛苦,因为我必须在任何地方都考虑生命周期。你不能只是摆脱它们。
后来我发现了第二个问题,而且问题更深:由于需要拥有数据,API 的许多用法变得更加困难,或者效率更低。
当结构体引用数据时,您必须保留引用的数据。当它是一些动态数据时,这可能会很烦人:你不能只传递结构而忘记底层数据(好吧,你可以但你不想)。
这个问题没有通用的解决方案。我创建了替代结构,以帮助在 Termimad 中处理它,但我仍然后悔最初没有做出让我的库结构拥有数据的简单选择。
不是每个人都会犯这个错误,但那些犯错的人可能会为此付出很长时间。
对于新的 Rust 开发人员来说,如何避免这个错误的简短初始版本是:在设计新库的结构时,更喜欢拥有数据。不要过早地使用基于引用的结构进行优化。
因为克隆数据以将它们传递给 API 很容易(而且成本也不高),但有时保留数据以便您可以传递引用是非常痛苦的。
 
错误 8:忽视非标准库
如果标准库中似乎没有某些东西(有时甚至是),请查找“非标准”库。
例如,这些 crate 是许多程序使用的标准的、高质量的库,你不能像忽略它们一样忽略它们std:

  • regex : 每个人如何在 Rust 中使用正则表达式
  • crossbeam : 一个高效便捷的通道库
  • serde:在 Rust 中进行序列化和反序列化的自然方式
  • rayon:一个非常简单易用的数据并行库
  • rand : 伪随机生成的默认选择

有许多问题存在多种解决方案,因此选择不会很明显,但很容易找到它们并进行比较。询问谷歌并搜索crates.iolib.rs,阅读自述文件(忽略“极快”的断言)并检查星星和家属的数量,四处询问。
 
错误九:使用unsafe、滥用unwrap
nsafe是很有用,是的,它是用来使用的。
但是您在学习 Rust 时可能不需要它。
如果您正在构建一些正常的东西,并且您遇到了文档中要求的unsafe函数,请再看一遍:附近可能有一个安全的解决方案。并且unsafe不是偷工减料并使代码更快的神奇解决方案。
至于unwrap,它在面向新程序员的文献中有点过于存在,因为它出现在大多数 Stack Overflow 答案和大多数文档片段中。
。。。
一个流行的中间立场,在原型设计或编写一个简短的片段时,使用expect来帮助说明为什么你认为这种情况不应该发生。
选择一种流行的错误管理库,在需要时使用Result正确声明你的函数,你的生活会更轻松。
 
错误10:不看资料
Rust 文档通常被认为是优秀的。
您阅读精美源代码的次数越多,您编写精美代码的速度就越快。
 
错误 11:从一开始就设计一切
Rust 使重构变得特别容易:编译器会指导您进行更改,直到代码再次保持一致。
一砖一瓦地构建您的东西并并行完善全局计划,它不需要完整或保持不变