Rust借用检查器真的那么具有挑战性吗?


1、如果您来自 JavaScript 或 TypeScript 等 GC 语言,它会迫使您思考以前不需要考虑的事情。
如果您来自 C 或 C++ 等手动内存管理语言,那么它只是对您应该已经执行的围绕所有权的心理计算的语法级和编译器级支持。在这种情况下,我认为它使编写代码变得更加容易。
所以,既然你属于前一类:是的,这是你需要努力解决的问题。

也就是说,“网上的人”喜欢抱怨事情,而且实际上并不像他们听起来那么糟糕 :
语法和编译器消息使值在何时何地“移动”、什么值被“拥有”以及什么值变得非常清楚。
因为值是“借来的”。
它永远不会像让垃圾收集器为您解决那么容易,但它比您想象的要容易得多。
生命周期有点棘手,需要更长的时间才能适应,但它们最终也确实有意义。

2、Rust 是唯一带有借用检查器的主流语言,而且它是一个相对新颖的概念/方法,没有像 OOP 或 FP 那样被彻底探索。
借用检查器施加了介于“一切都是不可变的”函数式方法和“一切都是可变的”命令式方法之间的限制。可以说,它保留了两者的大部分优点。
大多数摩擦来自于不习惯围绕这些限制来设计代码(并最终利用它们)。需要时间来适应并“感受”借用/所有权系统,因此您可以在借用-检查循环进入死胡同之前预见到问题。

3、如果您习惯于更实用的(映射map/过滤器filter)编码风格,您将不会遇到太多麻烦。如果您习惯了更加意大利面的面向对象风格,那么这可能会很困难。

4、不是很难通过“借用检查器”,而是看看当代码开始增长并且您还添加其他内容(例如泛型、“链接列表”式结构)时,很容易产生混乱。
当你需要编写“可读、干净的代码!”时,借用检查器并不能帮你实现。

5、熟悉 C++11 的智能指针(特别是 std::unique_ptr)和移动语义会给你一个良好的开端。

6、 Rust 所有权系统非常非常困难的原因:
我想要达到一个水平,我可以查看为trait/结构/枚举实现的复杂函数:

  • 这个函数可能是某些多种类型的泛型,
  • 可能具有引用和生命周期,具有特征边界,
  • 在其主体中,可以使用具有多个字段/关联数据、迭代器和并发代码的其他结构/枚举,
  • 甚至可能使用宏、框和外部库

并如果能以相当高的准确度快速确定,在我的脑海中清楚地了解他们的所有权限每个字段以及引用和取消引用等(当它们获得、丢失、重新获得读/写/拥有/流时)、堆栈帧、堆数据以及函数中每个相关行的它们之间的指针行。

如果我确实看到一些编译错误,我希望能够在我的脑海中以细粒度的方式在权限/堆栈帧/堆数据的上下文中推理错误,并了解它们根据内部操作的行为方式。

7、如果您尝试使用类和继承来抽象所有内容,那么您将很难学习 Rust。
如果您尝试使用接口和组合来抽象所有内容,那么您会更容易一些(学习如何通过静态/动态调度使用特征)。
如果您以函数式方式思考(您喜欢使用 map()、reduce()、filter() 并将所有内容都变成一大串函数调用),那么您可能会度过一段相当简单的时光,偶尔会出现问题。(了解 Fn、FnMut 和 FnOnce 特征以及它们的含义、如何使用它们,当您遇到问题时会有很大帮助。)
无论您喜欢哪种抽象,来自垃圾收集语言的您在尝试掌握“它能活多久?”的概念时都会遇到一些障碍。