持续创作,加速成长!这是我参与「掘金日新计划 · 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 开发。
更多详细信息,请对照参考资料提供的文档内容!