持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
学习脉络
- 初始化环境 --
rustup
&cargo
- 使用 VSCode 进行开发 -- 相关插件和配置
- Rust 基础语法
- 项目实战
💡 本章的重点是通过对比 Node.js 工具链,帮助你快速理解 Rust 的基础知识
为什么要学Rust?
Rust 对 WebAssembly 的工具和支持度高。因此可以用 Rust 来写 CPU 密集型的 JavaScript 逻辑,然后编译成 WebAssembly 来运行。
使用 rustup
安装 Rust
rustup
是 Rust 的安装和管理工具,并且官网推荐使用 rustup 安装 Rust。rustup
对应 Node.js 的 nvm
。
rustup
可以管理 Rust 安装过程,以及额外的目标文件(如 WebAssembly),还有一些核心工具,比如 cargo
(Rust 的 npm
) , clippy(Rust 的 eslint
), rustfmt
(Rust 的 perttier
),我们将在后面逐渐介绍他们。
相关介绍
rustup
将 rustc
和 cargo
等工具安装在 cargo 的 bin 目录下(Unix系统在$HOME/.cargo/bin
,Windows系统在%USER%.cargo\bin
),但这些工具只是 Rust 工具链中组件的代理,真正工作的是工具链中的组件。通过 rustup
的命令可以指定使用不同版本的工具链。
你可能会经常见到以下名词,我将为你分别介绍他们:
- channel: Rust 发布在三个不同的"channel"上:stable、beta 和 nightly。
- toolchain: 一套 Rust 组件,包括编译器及其相关工具,并且包含 channel、版本及支持的平台信息。
- target: 指编译的目标平台。
- component: toolchain 是由 component 组成的。
- profile: 为了方便对 component 进行管理,使用 profile 定义一组 component。
Channels
Rust 发布在三个不同的"channel"上:
- stable版本: Rust 的稳定版本,每 6 周发布一次。
- beta版本: Rust 的公开测试版本,将是下一个stable版本。
- nightly版本: 每天更新,包含以一些实验性的新特性。
通过 rustup 相关命令可以选择使用不同版本的 Rust,默认安装的是 stable 版本。
Toolchains
工具链的标准命令格式:
<channel>[-<date>][-<host>]
<channel> = stable|beta|nightly|<version>
<date> = YYYY-MM-DD
<host> = <target-triple>
Components
工具链由若干组件构成,通过 rustup component list
命令可以查看所有可用和已经安装的组件。
rustup 默认安装的组件:
- rustc — Rust 编译器。
- rust-std — Rust 标准库。
- cargo — 包管理和构建工具,类似于 Node.js 的
npm
和 Java 的Maven
和Gradle
。
- rust-docs — Rust 文档。
- rustfmt — 用来格式化 Rust 源代码。
- clippy — Rust 的代码检查工具。
Profiles
不同的 profile 包含不同的组件,安装 rustup 时有三种 profile 可选:
Profile | components |
---|---|
minimal | rustc, rust-std, cargo |
default | rustc, rust-std, cargo, rust-docs, rustfmt, clippy |
complete | all |
💡 可以使用
rustup set profile
命令来修改profilee.g.
rustup set profile minimal
rustup命令
rustup show
可以查看当前安装内容。
rustup completions
可以帮助启用一些工具的 CLI 的语法自动补全,比如rustup
和cargo
。
rustup component
可以允许添加额外的组件。
rustup update
可以更新到最新版。
rustup install stable|nightly|1
可以安装一些特定的版本
默认情况下,rustup 会安装最新的 rust
和 cargo
Npm
到 Cargo
cargo
是一个 Rust 的包管理器和项目构建工具,用起来很像 Node.js 中的 npm
。主要功能包括:
- 创建和管理 Rust 的模块。
- 调用 rustc 或其他工具一同构建项目。
- 拉取和管理项目依赖。
cargo
默认从 crates.io 下载依赖。类似 npmjs.com ,你可以注册账户然后发布自己编写的模块。
项目配置文件
在 node.js 中是 package.json
,在 Rust 中是 Cargo.toml
。
Cargo 的配置清单是 toml 格式,而非 JSON 格式,这跟习惯的 npm 的 package.json 不一样。Cargo 使用 Cargo.toml
文件来管理如何下载依赖、如何运行测试、 如何打包项目(还有一些其他配置项)。
Toml 交换格式
Toml(Tom’s Obvious, Minimal Language),是目录最优秀的配置文件格式方案。TOML 被设计成可以无歧义地被映射为哈希表,从而被多种语言解析。
注释
使用 #
注释
字符串
Multi-line basic strings
:保留换行符,行结束反斜杠来修剪任何非空格字符前面的空格
str1 = """
Roses are red
Violets are blue"""
str2 = """\
The quick brown \
fox jumps over \
the lazy dog.\
"""
Literal strings
:不支持转义,所见即所得
path = 'C:\Users\nodejs\templates'
path2 = '\User\admin$\system32'
quoted = 'Tom "Dubs" Preston-Werner'
regex = '<\i\c*\s*>'
- 因为没有转义,所以没有办法在由单引号括起来的字符串中写入单引号。此时需要多行字符:
re = '''\d{2} apps is t[wo]o many'''
lines = '''
The first newline is
trimmed in raw strings.
All other whitespace
is preserved.
'''
数字
支持 整数、浮点数、无穷大、NaN 类型,同时可以加符号位。
# integers
int1 = +99
int2 = -17
# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex3 = 0xdead_beef
# octal with prefix `0o`
oct1 = 0o01234567
oct2 = 0o755
# binary with prefix `0b`
bin1 = 0b11010110
# fractional
float1 = +1.0
float2 = -0.01
# exponent
float4 = 5e+22
float5 = 1e06
float6 = -2E-2
# both
float7 = 6.626e-34
# separators
float8 = 224_617.445_991_228
# infinity
infinite1 = inf
# positive infinity
infinite2 = +inf
# positive infinity
infinite3 = -inf
# negative infinity# not a number
not1 = nan
not2 = +nan
not3 = -nan
时间
支持时间类型。
# offset datetime
odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00
# local datetime
ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999
# local date
ld1 = 1979-05-27
# local time
lt1 = 07:32:00
lt2 = 00:32:00.999999
创建新项目
在 node.js 中是npm init
,在 Rust 中我们用 cargo init
和 cargo new
。
cargo init
会初始化当前所在目录。cargo new
会初始化一个新的目录。
安装依赖
在 node.js 中使用 npm intall [package]
。
在 Rust 中,如果安装了 cargo-edit,我们用 cargo add [package]
$ cargo install cargo-edit
这个工具会提供4个新的指令: add
, rm
, upgrade
和 set-version
。
安装全局工具
在 node.js 中是 npm install --global
,在 Rust 中是 cargo install
。
cargo install
可以用来下载、构建和把可执行文件放到 cargo 的 bin 目录。如果用 rustup
安装 rust
,那么这些依赖包是放在一个本地用户目录里的(通常是 ~/.cargo/bin
)。
💡 不需要用
sudo cargo install
来安装。
运行测试
在 node.js 中是 npm test
,在 Rust 中是 cargo test
。
通过 cargo test
的命令,cargo 会自动运行单元测试、集成测试和文档测试。
发布模块
在 node.js 中是 npm publish
,在 Rust 中是 cargo publish
。
和 npm 一样,你需要在 crates.io 注册一个账号,然后设置一些登录认证的细节。然后跟着指示就能发布自己的 rust 模块。
执行任务
- 在 node.js 中是
npm run [script]
来运行配置好的脚本。在 Rust 中则并不一定。有一些指令可以运行常规的任务;但是其余的任务,会需要你自己实现。
- 在 node.js 中可以使用
npm run start
来启动服务器、或者执行代码(前提是你在package.json中配置好了运行脚本)。在 Rust 中,可以使用cargo run
。 甚至可以用cargo run --example xxx
来自动执行 example 代码。
- 在 Rust 中可以使用
cargo bench
测试性能。
- 在 node.js 中可以使用
npm run build
来运行 webpack、vite、或者其他打包工具。在 Rust 中使用cargo build
。
- 在 node.js 中可以使用
npm run clean
来移除临时的、或生成的文件(配置rimraf /node_modules
)。在 Rust 中,可以用cargo clean
来清除构建目录(默认是target
)。
- 在 node.js 中可以使用
npm run docs
来生成文档(使用第三方文档生成库)。在 Rust 中是cargo doc
。
- 对于代码生成、预编译这些步骤,cargo 支持在执行主流程编译阶段之前,编写构建脚本(build scripts) 来实现。
Makefile
JavaScript 的项目里,因为使用了 npm
内建的任务执行器,所以很少看到 Makefile
。但在 Rust 中,手写 Makefile
依然很常见。just 在保持了 Makefile
相似语法的同时,消除了它的很多缺陷。安装 Just
:
$ cargo install just
其他的同类工具有 cargo-make
和 cargo-cmd
。
工作空间和单仓库
npm
和 cargo
这两个包管理器,都使用工作空间(workspace)的概念,以管理大项目中的小模块。在 Rust 项目的根目录里创建 Cargo.toml
文件,其中有一个 [workspace]
配置入口。这个入口是用来描述这个工作空间内哪些可以包括进来、哪些是被排除出去的。简单到像这样:
[workspace]
members = [
"crates/*"
]
相互依赖的工作空间的成员,可以将本地目录作为自己的依赖项。例如:
[dependencies]
other-project = { path = "../other-project" }
💡 新发布的*
npm v7.7.0
*版本中开始支持workspace
特性。
其他一些工具
cargo-edit
看到这里,我想你已经安装了这个工具。它提供了 cargo add
和 cargo rm
等命令,用来管理包依赖。
安装 cargo-edit
:
$ cargo install cargo-edit
cargo-workspaces
cargo workspaces
或 cargo ws
,简化了创建、管理工作空间和成员的流程。它借鉴了 node 的 lerna
,补充了cargo
没有实现的功能。 它最重要的功能之一,是可以自动发布工作空间的成员,用已发布的版本替换本地依赖。
安装 cargo-workspace
:
$ cargo install cargo-workspaces
💡
workspaces
是复数。不要错误安装成了cargo-workspace
cargo-expand
之后我们会学习宏(macros)
。宏在 Rust 中非常常见。在第一个 Hello World 程序中,100%的逻辑会封装在一个宏之中。宏很好用,可以提高你的代码复用率。但是宏也很难学习和调试。 cargo expand
可以帮助你更好地写宏。
cargo-expand
需要用到Nightly版的工具链。安装命令:
rustup install nightly
安装 cargo-expand
命令:
$ cargo install cargo-expand
安装之后,可以执行 cargo expand [method]
来打印 rustc 编译之后全量生成的源码。
cargo expand
接收一个方法名参数,而非文件路径。 执行cargo expand main
不会展开 src/main.rs,它会展开文件根目录的main()
方法。常规目录结构下, 如果要展开一个文件src/some_module/another.rs
,需要执行cargo expand some_module::another
。这块内容的具体讲解在模块系统。
如果执行了 cargo new
命令来进行测试,那么 src/main.rs
会是这样的:
fn main() {
println!("Hello, world!");
}
💡 标准输出是使用
println!()
宏来完成。println后面的感叹号代表这是一个宏,而不是一个函数。可以把它理解为一种安全版的编译器语法扩展,和c/c++中的宏安全不是一个东西。Rust之所以使用宏,而不是函数,是因为标准输出宏可以完成编译期格式检查,更加安全。
然后使用 cargo expand
来看下生成了什么代码:
$ cargo expand main
代码内容如下:
fn main() {
{
::std::io::_print(::core::fmt::Arguments::new_v1(
&["Hello, world!\n"],
&match () {
() => [],
},
));
};
}
总结
利用 npm
→ cargo
的对应关系,相信你就能很快地将前端开发经验转移到 Rust
开发上,以帮助你的 Rust 学习。接下来我将向你介绍利用 VSCode 进行 Rust 开发。
更多详细信息,请对照参考资料提供的文档内容!