【Rust】前端入门rust开发 | rustup与cargo

657 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

学习脉络

  1. 初始化环境 -- rustup & cargo
  2. 使用 VSCode 进行开发 -- 相关插件和配置
  3. Rust 基础语法
  4. 项目实战

💡 本章的重点是通过对比 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),我们将在后面逐渐介绍他们。

安装链接:www.rust-lang.org/zh-CN/tools…

相关介绍

rustuprustccargo 等工具安装在 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 的 MavenGradle
  • rust-docs — Rust 文档。
  • rustfmt — 用来格式化 Rust 源代码。
  • clippy — Rust 的代码检查工具。

Profiles

不同的 profile 包含不同的组件,安装 rustup 时有三种 profile 可选:

Profilecomponents
minimalrustc, rust-std, cargo
defaultrustc, rust-std, cargo, rust-docs, rustfmt, clippy
completeall

💡 可以使用rustup set profile命令来修改profile

e.g. rustup set profile minimal

rustup命令

rustup show 可以查看当前安装内容。

rustup completions 可以帮助启用一些工具的 CLI 的语法自动补全,比如 rustupcargo

rustup component 可以允许添加额外的组件。

rustup update 可以更新到最新版。

rustup install stable|nightly|1 可以安装一些特定的版本

默认情况下,rustup 会安装最新的 rustcargo

NpmCargo

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 被设计成可以无歧义地被映射为哈希表,从而被多种语言解析。

注释

使用 # 注释

字符串

  1. Multi-line basic strings :保留换行符,行结束反斜杠来修剪任何非空格字符前面的空格
str1 = """
Roses are red
Violets are blue"""
str2 = """\
  The quick brown \
  fox jumps over \
  the lazy dog.\
  """
  1. Literal strings :不支持转义,所见即所得
path = 'C:\Users\nodejs\templates'
path2 = '\User\admin$\system32'
quoted = 'Tom "Dubs" Preston-Werner'
regex = '<\i\c*\s*>'
  1. 因为没有转义,所以没有办法在由单引号括起来的字符串中写入单引号。此时需要多行字符:
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 initcargo new

cargo init 会初始化当前所在目录。cargo new 会初始化一个新的目录。

安装依赖

在 node.js 中使用 npm intall [package]

在 Rust 中,如果安装了 cargo-edit,我们用 cargo add [package]

$ cargo install cargo-edit

这个工具会提供4个新的指令: add, rm, upgradeset-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-makecargo-cmd

工作空间和单仓库

npmcargo 这两个包管理器,都使用工作空间(workspace)的概念,以管理大项目中的小模块。在 Rust 项目的根目录里创建 Cargo.toml 文件,其中有一个 [workspace] 配置入口。这个入口是用来描述这个工作空间内哪些可以包括进来、哪些是被排除出去的。简单到像这样:

[workspace]
members = [
  "crates/*"
]

相互依赖的工作空间的成员,可以将本地目录作为自己的依赖项。例如:

[dependencies]
other-project = { path = "../other-project" }

💡 新发布的*npm v7.7.0*版本中开始支持 workspace 特性。

其他一些工具

cargo-edit

看到这里,我想你已经安装了这个工具。它提供了 cargo addcargo rm 等命令,用来管理包依赖。

安装 cargo-edit

$ cargo install cargo-edit

cargo-workspaces

cargo workspacescargo 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 () {
                () => [],
            },
        ));
    };
}

总结

利用 npmcargo 的对应关系,相信你就能很快地将前端开发经验转移到 Rust 开发上,以帮助你的 Rust 学习。接下来我将向你介绍利用 VSCode 进行 Rust 开发。

更多详细信息,请对照参考资料提供的文档内容!

参考资料

  1. 安装Rust
  1. Rust Std Libarary
  1. Crates
  1. rustup
  1. just工具
  1. cargo-edit