作者:51CTO讲师张汉东 **
文章源自:https://zhuanlan.zhihu.com/p/21307896**
本文以学习Rust为例,分享一些我的学习方法,共勉!此文也是Rust发布一周年北京聚会的分享整理。
一、我为什么学习Rust语言?
我是一名Ruby程序员,Rubyist,众所周知Ruby是一门面向对象语言,所以我就一直和面向对象打交道了好多年,虽然Ruby语言也吸收了函数式语言的特性,但并不纯粹,总的来说,Ruby还是一门面向对象语言,它的抽象程度很高。我个人也不是一个对编程语言有特别偏好的那种人,我认为每种语言都有其适用场景,语言背后的思想才是最重要的。一直搞Ruby,现在感觉是时候从一个Ruby程序员成长为程序员了。
我听说Rust语言,是在去年差不多这个时候,Rust语言1.0版正式发布。 当时还有很多新的语言:golang、elixir、crystal等,但是在我眼里,最具鲜明特点的语言就是Rust, 当然Elixir也是非常不错的语言,我也在同时学习Elixir,但主要的精力还是侧重在Rust的学习之上。
Rust的鲜明特点主要有:
- 无GC、无VM(基于LLVM)
- 内存安全
- 强类型+静态类型
- 多范式
- 零运行时开销
- 系统编程语言
其实当时在选择Rust学习之前,我正在寻找一门新的语言去学习,主要是为了满足我以下学习需求:
- 因为一直专注于Ruby语言,Ruby语言的抽象度高,所以我想找一门系统编程领域的语言去深入学习,用于扩展自己的知识体系。考虑过C++,但是传说中没有人能精通C++,以这点来看,我还不敢踏入其中,怕是个无底洞。C语言,自己也了解,但是说实话,我对使用C暂时还提不起兴趣。
- 也想找一门函数式编程范式的语言深入学习一下,比如Haskell,单从语法层面,感觉不是很好,不如Rust吸引我。Rust的缩写关键字,以及很多语法结构,我看着都比较亲切。
就在我选择的时候,正好赶上了Rust发布了1.0,就想去好好了解了一下,感觉学习Rust,正好可以同时满足自己的学习需求,更重要的是,Rust语言的设计,深深的吸引了我,比如无GC,但可以实现内存安全,这就强烈的引起了我的好奇心,想去了解它;再比如无VM的特性,直接编译为LLVM IR,个人认为LLVM也是值得花时间学习的,毕竟是个趋势;再比如Rust的类型系统,值得好好花时间去学习一下类型系统对于一门语言来说是多么的重要,我用Ruby完全没有这种感觉。综合这些原因然后就选择了Rust。
至于Rust未来的发展如何,能找到多少钱工资的工作,我完全没有关心过,我学习Rust的唯一目的,就是扩展自己的知识体系。
二、前期学习的懵逼
所以,现在知道了,我学习Rust之前的背景是:无系统编程语言基础。
对于了解过Rust的人都知道,Rust的概念相当多:
- 所有权、租借、生命周期、Copy/Clone
- 内存布局、Scope
- 函数
- 模式匹配
- Trait
- 泛型与类型系统
- 智能指针
- safe和unsafe
- 宏还有两种: 普通宏(macro_rules!定义的)与 可以定义编译器插件的procedural macro
- 包系统
- 安全的多线程并发编程
- Option/Result 错误处理
上面的很多概念,对我来说,熟悉而又陌生。但是陌生的还是占绝大多数,有C++或Haskell基础的人,学Rust也许可以快速上手,但是对于我来说就不行了。面对这些概念,我告诉自己,一定要冷静!内心降到绝度零度!
三、调整后的学习路线
冷静以后,我规划了下列的学习路线:
- 首先,我要分别理清楚这些概念分别是什么
- 其次,遵循Rust的设计原则,理清这些概念背后的脉络
- 实战中深入学习。
3.1 理清概念
理清概念的过程比较曲折。
第一遍,先是从 Rust官方出的rust book看起,但是此书组织的很不科学,不适合我这样的初学者,书本并非循序渐进的,所以后来Rust官方也重写了这本书,进度比较慢,还未发布。
硬着头皮看了一遍,概念依然不够清晰,但是概念看的多了,最少让我消除了对Rust的陌生感。
第二遍,跟着Rust by example边练习边学习, 但是练到第八章内容就感觉很困难了,还是卡在了概念上。再加上工作也比较忙,于是我就暂停学习了。
一晃就大半年过去了。。
第三遍开始,是缘于Rust社区Mike组织了RustPrimer一书,记得是去年春节前组织的,没几个月就写完了,让我感受到了社区的激情。RustPrimer看完一遍,再加上线上对大神们的请教,对于一些关键概念,比如所有权,大概清楚是怎么回事了。
3.2 理清脉络
虽然有些概念清楚了,但感觉自己对Rust的认识还是零零碎碎的,这些概念并没有形成自己的知识体系。学习一门新语言,我的做法是先从它的设计哲学开始,把该语言的所有概念串起来,这些概念不可能是零散的,尤其是对一门高度一致性的语言来说。如果这些概念没有形成体系,我就无法开始对这门语言的编程实践,因为心里没底。
我们来看一下Rust官网的介绍:Rust 是一门高性能、内存安全,并保证线程安全的系统编程语言。
一门语言的语言特性,是为它的设计目标服务的。
那么第一个目标:高性能,是如何实现的呢?基于LLVM,无GC,低运行时开销,零成本抽象,Rust有个强大的编译器。
后二个目标: 内存安全。在我学习的过程中,一度以为用Rust写代码,就肯定是安全代码了,也一度以为,Rust只有所有权机制是为这个目标服务的。到后来才发现自己的认识是错误的。首先内存安全这个概念很大,我现在认为它包含了四点:
- 内存安全。基于所有权机制,但也并非只有所有权,还有Copy/Clone等行为;以及内存布局默认在栈上分配内存,而把堆分配做为可选;生命周期避免了悬空指针;RAII机制来保证分配的内存在出了作用域就得到自动释放;这些相关语言特性都是来保证内存安全。
- 没有绝对的安全。Rust为你提供安全机制,也为你提供不安全的分界线。所有权机制是有界限的,也就是说安全是有界限的,Rust允许你把安全和不安全的代码分开,这样更容易保证安全。比如当你调用FFI、解构裸指针等。
- 类型安全。强大的Trait,可以静态分发,也可动态分发;以及基于Trait的泛型机制,ADT/模式匹配的支持,Option/Result类型安全的错误模式;严格的编译器类型检查。
- 并发安全。基于所有权机制,Rust保证并发中的内存安全,避免了数据竞争。而Rust里保证线程安全的两个记号Trait,Sender和Sync都是基于unsafe trait实现的。
我们也知道Rust是一门多范式语言。刚开始学的时候,我有个疑问:多范式语言,那么平时编程的时候侧重哪种范式呢?后来发现我的问题是多余的。多范式语言只是一些语言特性,它的目标还是为内存安全目标服务。
基于Struct和Impl,加上方法调用语法,可以写出面向对象范式的代码。比如可以写出像Ruby的链式调用代码。而基于Trait的唯一接口方式,简化了所谓的多态,也为类型系统提供了方便。
Rust也支持了函数式语言特性,包含高阶函数、闭包、强大的模式匹配等机制。
Rust的元编程能力也是非常棒的,最常用的是普通宏 macro_rule!, 这其实是一个特殊的函数,依赖强大的模式匹配,帮助你进行语法扩展。你所要做的,就是写出你要实现的宏的分词规则。另外一种就是procedural macro,可以用来实现编译器插件,它是直接操作AST,但是这个宏感觉不如Lisp系语言那种直接暴露AST操作起来爽。据说未来版本还会增强procedural macro的能力。
再一个就是智能指针系列,说实话,我对这部分内容还是不太理解,只知道它是Rust所有权机制的补充,为了满足更多的编程需求。
Rust的另一个特点就是工程化工具很棒,Cargo,可以快速帮你构建一个工程。不过至今我还没有写过一个完整的工程,这是我的下一步学习计划。
最终,我的脑中就串起了图中这些的概念结构,我认为现在Rust对我来说一点都不神秘了。我终于可以心里有底的踏出下一步了。
此结构图Github地址:GitHub - RustStudy/learn_rust_roadmap: Rust概念梳理
如有错误,请指出,共同学习,多谢!
觉得文章不错的朋友,欢迎点赞、分享哦。
另外,张老师的新课诱人的Ruby-视频课程入门篇与进阶篇也在51CTO学院上发布。
对Ruby感兴趣的朋友,可以前来观看、学习。