Rust学习笔记(1)
Rust是开源大佬Mozilla在2014年发布的一款面向系统级应用和底层应用开发的程序设计语言。在这之前,Google在2009年发布了Go语言,并且取得了不小的成功,比如Docker,这款极为强大且好用的容器引擎是使用Go构建的。不过Rust在发布的三年后也已经收获了一批拥趸,第一个面向很多用户的项目,Firefox Quantum版本中的CSS引擎(是用Rust写的)也即将发布了。我已经看过不少PL大师和一些搞编译器部分的大佬在狂吹Rust,Rust的社区也日渐壮大。
作为目标都是干掉C/C++,面向底层应用开发的程序语言,Go和Rust其实无形中有一种竞争关系(BTW,浏览器上,Google也一直在和Mozilla竞争)。7月的时候我也看了一下Go,看的很少,被语法恶心到了一下,可能是因为看得比较少的原因,之后应该会再看一下;但是从我前天晚上点开Rust开始,我却像上瘾一样被这门语言深深的吸引了,它的内部一些设计让我看到了Rust的优越性:
- 面向底层开发,高效的C绑定与极小运行时
- 零开销抽象,独特却先进的内存管理模型
- 线程无数据竞争,数据的所有权控制
- 极其前沿的语言特性,对FP的出色支持
等等等等。在看了这么一段时间之后,我已经深深地爱上了它,并且将把这门语言作为我C++的后备和全新的主力。
说了这么多,写点简单的东西作为笔记吧。
一、安装与配置
安装与配置十分简单。这里就要吹一波,Rust的工具链十分好用,你不需要任何IDE,一个文本编辑器就够了。
我的配置环境很简单:
- Elementary OS 0.4.1 based on Ubuntu 16.04.1
- VS Code Latest Stable
那安装步骤实际上可以说是傻瓜式了:
在终端中运行:
1
curl https://sh.rustup.rs -sSf | sh
就行了。Rust的安装程序会把你需要的自动配置好。之后你重启一下shell就行。
验证安装:运行一下
rustc --version
和cargo --version
。这两步如果都返回一个带版本号的提示信息就代表配置完成了。如果没有,找到你的安装路径,一般是~/.cargo/bin
,加进环境变量即可。
安装之后,来到VS Code,有官方的插件和一个用户写的。我用的是那个用户写的,安装然后Reload就行。可以用ext install vscode-rust
。
这个插件的工作方式有两种:
- Legacy:这个模式下是插件配合,Stable Channel下可以正常工作,但是作者说这个模式做的虽然好,但是RLS模式更好,可能会废弃,所以现在可以用,也比较省心,但是未来要记得更换。
- RLS(Rust Language Server):Rust官方写了Language Server,也就是有了IDE级别的辅助开发能力,我更推荐这个模式。不过现在RLS还是预览版,如果要使用需要自行切换工具链。
我用了RLS模式。具体安装流程如下:
从nightly channel安装
1
rustup install nightly
安装依赖&Racer
1 2 3 4
rustup component add rls-preview --toolchain nightly rustup component add rust-analysis --toolchain nightly rustup component add rust-src --toolchain nightly cargo install racer
VS Code配置
打开用户配置文件,添加:
1 2 3 4
"rust.mode": "rls", "rust.rls": { "useRustfmt": true }
这就配置好了。其他编辑器请自己找配置教程。
还要注意,这里配置之后,默认的工具链还是在stable下,我们可以这么切换工具链:rustup default nightly
。这样整个工具链会整体切换到nightly下面,包括cargo。如果你需要换回stable,只需要rustup default stable
即可。另外,更新的时候使用rustup self update
和rustup update
,所有版本都会获得更新。
注意,nightly顾名思义,每夜版,是最前沿的开发版,可能会出现rls-preview更新跟不上等等问题,假如遇到了,可以考虑切换到beta channel,具体方式同上。如果发现VS Code无法使用beta channel下面的rls分析的话,把配置文件中
"rust.rustup":{"nightlyToolChain"}
后面的字段改成beta就行。
简单一提几个命令:
- 编译一个
.rs
文件:rustc hello.rs
- 新建一个库项目:
cargo new helloworld
- 新建一个应用程序项目:
cargo new helloworld --bin
- cargo编译:
cargo build
- cargo编译并运行:
cargo run
- cargo编译发行版:
cargo build --release
- cargo生成文档:
cargo doc
- cargo测试:
cargo test
差不多就这些了,更多的请自己查文档。
二、简单语法
Rust的语法很容易理解,不过也有和传统语言不同的地方。
首先是程序主体,main()
函数仍然是程序入口:
|
|
当然,这个是程序项目,库项目不需要这个东西。
变量的声明需要讲讲:
|
|
简单吧?要注意的是,Rust用的是Hindley-Milner类型系统,这是一个十分现代的类型系统,如果用过Haskell的话会对这种类型系统十分熟悉。
Hindley-Milner类型系统:
简单来说,HM类型系统可以对你的变量类型进行自动推导,这样你就不用在每一次指定你的变量类型;同时,由于它强大的类型推导能力,当你进行函数应用的时候,会自动推导出你的程序每一步的函数调用、返回赋值等等类型是否一致,能在静态检查时扼杀大部分的调用错误。
这里要强调一下mut
关键字。Rust的变量是FP+IP的混合系统,在FP系统中,变量统一是不可变的,这很好理解,因为在函数式下变量和函数应用过程没有任何关系(参照我曾经写过的这篇文章),所以变量自然是不可变的。但是在我们的应用过程中很自然的需要一些可变变量,则我们使用mut
来声明变量就可以让它变得可变。
类型注解功能只是显式指出类型是什么,如果注解和编译器推导的有问题仍然编译不过。
变量声明还有其他内容需要讲,这一部分将在数据类型中有涉及。
数据类型之后讲,这一部分和很多内容有关。
流程控制下,Rust综合了很多语言的流程控制顺序。具体来说,有以下三种:
loop
循环1 2 3 4
loop { // 这个循环是确定的无限循环,你只能使用break退出 break; }
while
循环1 2 3
while count != 0 { count -= 1; // Rust没有--与++ } // 这就是我们熟悉的while循环
for
循环1 2 3
for i in v.iter() { // do something with i }
for
循环没看懂?有Python基础的程序员应该能立即看懂,但是只有Java或者C/C++背景的程序员可能有点难理解。简而言之,只要in
后面的对象是可迭代的,都能使用for
循环去遍历,可以看看Python或者Rust标准库文档里面的示例深入理解一下。
continue
和break
这两个关键字仍然可用。
我们考虑如下一段C++代码:
|
|
根据a
的不同值,我们得到不同的答案。当然,我们也可以使用switch
。在Rust中,我们将见到更加强力的一种语法:模式匹配。
|
|
模式匹配的启动由一个match
运算符引起,之后是一个表达式,可以是布尔表达式如if a == 25
,或者就是单纯的一个变量,如a
。大括号内部是匹配主体,由多个分支(arm)构成。
表达式与语句:
- 语句(Statements):执行一些操作但不返回值的指令
- 表达式(Expressions):计算并产生一个值
分支遵循如下格式:
|
|
前面是匹配成功的模式,后面是匹配成功后执行的表达式。比如,上面的15 => 16
意思就是:
|
|
这个匹配成功的表达式(即if_matched
)可以使用大括号括起来的一组表达式或者语句构成。
_
的意思是通配,也就是所有内容都可以匹配上。那既然都可以匹配上,怎么保证15不会匹配到_
上面呢?很简单,match
带来的模式匹配由上到下,也就是越靠前的优先级越高,我们匹配时从上往下匹配,直到匹配上为止。同时,Rust也会要求你必须穷尽匹配,比如上面的代码如果这么修改:
|
|
编译器会报错,因为匹配到除了15和16以外的值是没有对应分支的,这样这个匹配是无法穷尽的。所以,一个match
运算符中的模式匹配必须穷举所有可能的模式。到这你应该能体会到_
的用处了。
match
所能带给我们的方便和优越性都是来自HM类型系统的功劳。或许,现在你还不能看出它的强大之处,等我们之后讲解了Rust的枚举之后你再品味,就能体会到它的强大了。
简单语法的最后,提一下怎么向控制台打印:
|
|
打印的时候出现了三个新的点:宏与函数,模板字符串和Debug模式。第一个第三个都之后讲,这里重点讲模板字符串。
模板字符串是在JavaScript和Python通用的一种字符串格式化的语法。考虑如下C++代码:
|
|
这样读起来其实很难受,因为每一个标识符代表的意义不同,无论是人类去读或者编译器去parse都不容易。模板字符串则足够简单:
|
|
我们只需要处理{}
即可。当然,所有的参数都在这里面,比如我们可以指定顺序:
|
|
至于模板字符串的格式化参数,请查阅库文档。
下集预告
讲的好少啊…….
一篇能写下的东西也不多,其实就是官方的实例的精简版,哈哈。
下期会讲一下Rust设计里面我觉得最优秀的两个地方:所有权(Ownership)系统和Option
。主题应该是函数与变量和数据类型了。
我的主要参考资料是Rust 程序设计语言中文第二版,感谢翻译者和作者的辛勤工作!
See you soon~
Changelog:
2017.10.30 V1.0:最初版
2017.10.30 V1.1:添加必要链接,修正部分描述和结构,有关RLS部分修正