2024年五月月 发布的文章

Gopher的Rust第一课:建立Rust开发环境

本文永久链接 – https://tonybai.com/2024/05/10/gopher-rust-first-lesson-setup-dev-env

经过上一章的对Rust诞生演化的了解以及设计哲学的探讨后,如果你依然决定继续Rust编程学习之旅,那么欢迎你和我一起正式走进Rust学习和实践的课堂。

编程不是“纸上谈兵”,它是一门实践的艺术。编程语言的学习离不开动手实践,因此学习任何一门编程语言的第一步都是要拥有一个这门编程语言的开发环境,这样我们才可以动手编码,理论与实践结合,不仅加速学习效率,还能取得更好的学习效果。

在这一章中我们就先来学习下如何安装和配置Rust开发环境。如果你的机器上还没有Rust开发环境,那么就请跟我一起选择一种适合你的Rust安装方法吧。

第一步,我们先来挑一个合适的Rust版本。

2.1 选择Rust版本

2.1.1 Go与Rust发布版本与节奏的对比

《Go语言第一课专栏》讲解如何建立Go开发环境时,我首先讲解的也是选择Go版本。我们知道Go一年发布两次大版本,分别是每年的2月和8月,并且Go核心团队只对最近的两个大版本提供support。在处于support时间窗口中的时候,Go核心团队会发布一些补丁版本,修正及少量的严重问题或安全漏洞。比如Go 1.22版本是2024年2月份发布的,到2024年4月中旬,Go 1.22的最新补丁版本已经到了Go 1.22.2了。下图展示了Go版本发布的节奏以及support的窗口:

在Go中,我们可以选择最新稳定版(比如图中的Go 1.22.2)和次新稳定版(比如图中的1.21.8),这两个是Go社区选择最多的。此外,也可以选择某个特定的稳定版(因某种特殊原因,被阻塞在该版本上)以及tip版,其中tip版(master分支上的最新commit版本)主要用于体验最新的、尚未发布的功能特性或问题修复,或是contributor多使用tip版。

Rust的版本发布节奏与Go完全不同,因此Rust版本的选择逻辑与Go相比也就有所不同。下图展示了Rust的版本发布方法与节奏:

我们看到:Rust采用“6周一个稳定版”的滚动发布节奏,并且有三类版本:稳定版(stable)、公测版(beta)和nightly版,分别对应的是stable分支、beta分支和master分支。三个版本间是关联紧密的。

以图中的rust 1.77.0的发布为例,rust 1.77.0稳定版本的发布动作是这样的:

  • 基于当前beta分支(其实就是1.77.0 beta)创建新的stable分支,并tag 1.77.0;
  • 基于当前master分支(nightly版本)创建新的beta分支,并在新的beta分支上公测1.78.0版本,为六周后的1.78.0稳定版做准备;
  • 而master分支上继续开发v1.79.0的新特性,并每天发布Nightly版本。

之后,原1.76.0稳定版便会从support窗口删除,1.77.0进入Support窗口。如果新发布的1.77.0有紧急或安全问题需要修复,则通过补丁(patch)版本进行,比如rust 1.77.1、1.77.2等。

Rust这种“稳定一版,公测一版,开发一版”的“三路并发”的滚动开发节奏,显然要比Go的“稳定一版,开发一版”的“两路并发”节奏要快上很多。不过,频繁的更新可能对某些用户来说是一个挑战,需要他们不断学习和适应新的变化。另外,较快的演进速度也可能导致一些不稳定因素,需要开发者更加谨慎地使用新功能特性。

2.1.2 Rust的三类版本

选择Rust版本根据自己的角色和面对的场合来进行:

  • 对于大多数Rust开发者而言,最新的稳定版(stable)是最好和最明智的选择;
  • 也有少部分因为各种特殊原因,可能阻塞在某个特定的稳定版上;
  • Beta版contributor,或是想提前尝鲜下一个稳定版新特性的开发人员,可以临时使用beta版本;
  • Nightly版,主要针对的也是contributor,或是想临时尝鲜最新不稳定功能特性的开发人员。

Rust提供的安装和升级工具rustup可以灵活的在三类版本间切换:

rustup default beta
rustup default nightly
rustup default stable

切换后,rustup会自动同步该类版本到最新版:

$rustup default beta
info: syncing channel updates for 'beta-x86_64-apple-darwin'
info: latest update on 2024-04-11, rust version 1.78.0-beta.6 (27011d5dc 2024-04-09)
... ...

确定了要使用的Rust版本后,我们接下来就来看看究竟如何安装Rust。

2.2 安装Rust

2.2.1 使用rustup安装

和Go尽可以通过安装包或下载预编译二进制包进行首次安装不同,Rust官方提供了统一的Rust安装、管理和升级工具- rustup。 Rust官方在Linux和macOS上提供了“curl | sh”的一键式安装命令:

$curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

我们以Linux下安装rustup为例,看一下执行上面命令的过程和最终结果:

$curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
info: downloading installer

Welcome to Rust!

This will download and install the official compiler for the Rust
programming language, and its package manager, Cargo.

Rustup metadata and toolchains will be installed into the Rustup
home directory, located at:

  /root/.rustup

This can be modified with the RUSTUP_HOME environment variable.

The Cargo home directory is located at:

  /root/.cargo

This can be modified with the CARGO_HOME environment variable.

The cargo, rustc, rustup and other commands will be added to
Cargo's bin directory, located at:

  /root/.cargo/bin

This path will then be added to your PATH environment variable by
modifying the profile files located at:

  /root/.profile
  /root/.bashrc

You can uninstall at any time with rustup self uninstall and
these changes will be reverted.

Current installation options:

   default host triple: x86_64-unknown-linux-gnu
     default toolchain: stable (default)
               profile: default
  modify PATH variable: yes

1) Proceed with standard installation (default - just press enter)
2) Customize installation
3) Cancel installation

> // 敲击回车

info: profile set to 'default'
info: default host triple is x86_64-unknown-linux-gnu
info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'
info: latest update on 2024-04-09, rust version 1.77.2 (25ef9e3d8 2024-04-09)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
 14.9 MiB /  14.9 MiB (100 %)   3.7 MiB/s in  3s ETA:  0s
info: installing component 'rust-std'
 24.3 MiB /  24.3 MiB (100 %)   8.2 MiB/s in  2s ETA:  0s
info: installing component 'rustc'
 60.3 MiB /  60.3 MiB (100 %)   9.6 MiB/s in  6s ETA:  0s
info: installing component 'rustfmt'
info: default toolchain set to 'stable-x86_64-unknown-linux-gnu'

  stable-x86_64-unknown-linux-gnu installed - rustc 1.77.2 (25ef9e3d8 2024-04-09)

Rust is installed now. Great!

To get started you may need to restart your current shell.
This would reload your PATH environment variable to include
Cargo's bin directory ($HOME/.cargo/bin).

To configure your current shell, you need to source
the corresponding env file under $HOME/.cargo.

This is usually done by running one of the following (note the leading DOT):
. "$HOME/.cargo/env"            # For sh/bash/zsh/ash/dash/pdksh
source "$HOME/.cargo/env.fish"  # For fish

接下来按照提示执行下面命令,使得Rust相关的环境变量生效:

$. "$HOME/.cargo/env"
$which rustup
/root/.cargo/bin/rustup

. “$HOME/.cargo/env”这行代码也被追加到/root/.bashrc文件中,如果新启动一个terminal窗口,这行shell配置也会被执行,即rustup的环境变量也生效。

查看一下安装的rustup的版本:

$rustup -V
rustup 1.27.0 (bbb9276d2 2024-03-08)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.77.2 (25ef9e3d8 2024-04-09)`

同时我们看到:首次安装rustup时,如果选择“standard installation”,rustup会为我们安装一个最新的Rust stable版本,这里是1.77.2,我们可以通过rustup show命令查看已安装的rust工具链:

$rustup show
Default host: x86_64-unknown-linux-gnu
rustup home:  /root/.rustup

stable-x86_64-unknown-linux-gnu (default)
rustc 1.77.2 (25ef9e3d8 2024-04-09)

除此之外,rustup还在你的系统中都做了啥呢?我们下面来探索一下。

2.2.1.1 安装后的探索

根据rustup在安装过程中的提示,有两个路径是需要重点关注的。

一个就是\$HOME/.cargo,rustup将.cargo/bin加入到了\$PATH变量下,我们来看看.cargo下都有哪些目录和文件:

$tree -F .cargo
.cargo
|-- bin/
|   |-- cargo*
|   |-- cargo-clippy*
|   |-- cargo-fmt*
|   |-- cargo-miri*
|   |-- clippy-driver*
|   |-- rls*
|   |-- rust-analyzer*
|   |-- rustc*
|   |-- rustdoc*
|   |-- rustfmt*
|   |-- rust-gdb*
|   |-- rust-gdbgui*
|   |-- rust-lldb*
|   `-- rustup*
`-- env

.cargo下主要的目录就是bin,这里存放了日常rust开发时在命令行使用的所有cli命令,包括cargo(构建管理工具)、rustc(编译器)、rustdoc、rustfmt以及rustup自身等。

另外一个更值得关注的目录就是\$HOME/.rustup目录,这个目录下的内容较多,我们通过tree命令查看的结果如下:

$tree -F -L 3  .rustup
.rustup
|-- downloads/
|-- settings.toml
|-- tmp/
|-- toolchains/
|   `-- stable-x86_64-unknown-linux-gnu/
|       |-- bin/
|       |-- etc/
|       |-- lib/
|       |-- libexec/
|       `-- share/
`-- update-hashes/
    `-- stable-x86_64-unknown-linux-gnu

settings.toml是一个rustup配置文件,它的内容如下:

$cat .rustup/settings.toml
default_toolchain = "stable-x86_64-unknown-linux-gnu"
profile = "default"
version = "12"

[overrides]

这里的default_toolchain指示了当前默认使用的工具链版本为stable-x86_64-unknown-linux-gnu。这个版本也是一个target,Rust支持的不同平台上的target以及含义如下图:

.rustup下的另外一个值得注意的目录是toolchains,它下面存放了安装到本地的所有版本的toolchain,上面由于只安装了stable的最新版本,因此当前toolchains下只有一个stable-x86_64-unknown-linux-gnu目录。

值得注意的是.rustup中存储了rust工具链的所有内容,因此它的空间占用也着实可观:

$ du -sh .rustup
1.2G    .rustup

现在我们来切换默认版本到beta:

$rustup default beta
info: syncing channel updates for 'beta-x86_64-unknown-linux-gnu'
info: latest update on 2024-04-11, rust version 1.78.0-beta.6 (27011d5dc 2024-04-09)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
 15.1 MiB /  15.1 MiB (100 %)   3.4 MiB/s in  3s ETA:  0s
info: installing component 'rust-std'
 24.2 MiB /  24.2 MiB (100 %)   9.3 MiB/s in  2s ETA:  0s
info: installing component 'rustc'
 63.5 MiB /  63.5 MiB (100 %)   9.6 MiB/s in  6s ETA:  0s
info: installing component 'rustfmt'
info: default toolchain set to 'beta-x86_64-unknown-linux-gnu'

  beta-x86_64-unknown-linux-gnu installed - rustc 1.78.0-beta.6 (27011d5dc 2024-04-09)

我们看到rustup会自动下载安装最新的beta版本,安装后,我们再执行rustc -V来查看当前版本,我们发现结果已经变为了下面这样:

$ rustc -V
rustc 1.78.0-beta.6 (27011d5dc 2024-04-09)

这里值得注意的是,虽然我们执行的rustc是.cargo/bin/rustc,但.cargo/bin/rustc有些类似于一个指针,真正执行的是其“指向”的某个工具链版本的rustc,我们可以使用rustup which rustc来查看究竟执行的是哪个rustc:

$ rustup which rustc
/root/.rustup/toolchains/beta-x86_64-unknown-linux-gnu/bin/rustc

此时,.rustup目录下面发生了怎样的变化呢?我们来看看:

$ tree -F -L 3  .rustup
.rustup
|-- downloads/
|-- settings.toml
|-- tmp/
|-- toolchains/
|   |-- beta-x86_64-unknown-linux-gnu/
|   |   |-- bin/
|   |   |-- etc/
|   |   |-- lib/
|   |   |-- libexec/
|   |   `-- share/
|   `-- stable-x86_64-unknown-linux-gnu/
|       |-- bin/
|       |-- etc/
|       |-- lib/
|       |-- libexec/
|       `-- share/
`-- update-hashes/
    |-- beta-x86_64-unknown-linux-gnu
    `-- stable-x86_64-unknown-linux-gnu

我们看到toolchains下面多了一个beta-x86_64-unknown-linux-gnu目录,存放的就是刚刚安装的beta最新版本工具链。

现在我们在用rustup show命令查看已安装的rust工具链,其结果如下:

$rustup show
Default host: x86_64-unknown-linux-gnu
rustup home:  /root/.rustup

installed toolchains
--------------------

stable-x86_64-unknown-linux-gnu
beta-x86_64-unknown-linux-gnu (default)

active toolchain
----------------

beta-x86_64-unknown-linux-gnu (default)
rustc 1.78.0-beta.6 (27011d5dc 2024-04-09)

现在,我们切换回stable版本,由于stable版本之前已经安装完毕,也就无需下载和安装过程了:

$rustup default stable
info: using existing install for 'stable-x86_64-unknown-linux-gnu'
info: default toolchain set to 'stable-x86_64-unknown-linux-gnu'

  stable-x86_64-unknown-linux-gnu unchanged - rustc 1.77.2 (25ef9e3d8 2024-04-09)

2.2.1.2 安装和使用特定版本rust工具链

我们还可以使用rustup安装特定版本的rust工具链,比如通过下面的命令,我们安装stable版本的1.66.0:

$ rustup install 1.66.0
info: syncing channel updates for '1.66.0-x86_64-unknown-linux-gnu'
info: latest update on 2022-12-15, rust version 1.66.0 (69f9c33d7 2022-12-12)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
 19.0 MiB /  19.0 MiB (100 %)   4.4 MiB/s in  3s ETA:  0s
info: installing component 'rust-std'
 29.7 MiB /  29.7 MiB (100 %)   8.1 MiB/s in  3s ETA:  0s
info: installing component 'rustc'
 68.0 MiB /  68.0 MiB (100 %)  10.2 MiB/s in  6s ETA:  0s
info: installing component 'rustfmt'

  1.66.0-x86_64-unknown-linux-gnu installed - rustc 1.66.0 (69f9c33d7 2022-12-12)

info: checking for self-update

安装ok后,我们再来看看.rustup目录下的变化:

$tree -F -L 3  .rustup
.rustup
|-- downloads/
|-- settings.toml
|-- tmp/
|-- toolchains/
|   |-- 1.66.0-x86_64-unknown-linux-gnu/
|   |   |-- bin/
|   |   |-- etc/
|   |   |-- lib/
|   |   |-- libexec/
|   |   `-- share/
|   |-- beta-x86_64-unknown-linux-gnu/
|   |   |-- bin/
|   |   |-- etc/
|   |   |-- lib/
|   |   |-- libexec/
|   |   `-- share/
|   `-- stable-x86_64-unknown-linux-gnu/
|       |-- bin/
|       |-- etc/
|       |-- lib/
|       |-- libexec/
|       `-- share/
`-- update-hashes/
    |-- 1.66.0-x86_64-unknown-linux-gnu
    |-- beta-x86_64-unknown-linux-gnu
    `-- stable-x86_64-unknown-linux-gnu

我们看到toolchains下面多了一个1.66.0-x86_64-unknown-linux-gnu,那我们如何使用新下载的1.66.0 stable版本呢?有几种方法,下面逐一介绍一下。

我们可以使用rust工具链的“plus语法”在命令行上指定要使用的工具链,这个语法对cargo、rustc等工具链中的命令行程序都适用:

$ rustc +1.66.0 -V
rustc 1.66.0 (69f9c33d7 2022-12-12)
$ rustc +1.65.0 -V
error: toolchain '1.65.0-x86_64-unknown-linux-gnu' is not installed

$ cargo +1.66.0 -V
cargo 1.66.0 (d65d197ad 2022-11-15)
$ cargo +1.65.0 -V
error: toolchain '1.65.0-x86_64-unknown-linux-gnu' is not installed

注:cargo是Rust语言的官方构建系统和包管理器,它提供了一组命令行工具,可以自动化构建、测试和发布Rust项目。它还支持自动解析和下载依赖项,使得管理项目的依赖关系变得简单和可靠。Cargo是Rust生态系统中重要的工具之一,为开发者提供了高效和方便的开发体验。在后面的章节中我会详细介绍cargo。

对于要使用特定版本进行构建的rust项目,我们可以通过rustup override来指定版本号。下面就是一个这样的例子:

$cargo new hellorust
     Created binary (application) `hellorust` package
$cd hellorust/
$rustup override set 1.66.0
info: override toolchain for '/root/test/rust/hellorust' set to '1.66.0-x86_64-unknown-linux-gnu'

我们用cargo创建了一个新的hellorust项目,在hellorust项目下,我们执行rustup override来指定该项目使用1.66.0版本进行构建。

之后,我们分别在该项目目录下以及其他目录下执行rustc,我们看到输出结果如下:

~/test/rust/hellorust$ rustc -V
rustc 1.66.0 (69f9c33d7 2022-12-12)
$ cd ..
~/test/rust$ rustc -V
rustc 1.77.2 (25ef9e3d8 2024-04-09)

rustc override的原理其实是在$HOME/.rustup/settings.toml文件中添加了一些内容:

$cat .rustup/settings.toml
default_toolchain = "stable-x86_64-unknown-linux-gnu"
profile = "default"
version = "12"

[overrides]
"/root/test/rust/hellorust" = "1.66.0-x86_64-unknown-linux-gnu"

我们看到在overrides下新增了一条规则,指定了hellorust项目需要使用1.66.0-x86_64-unknown-linux-gnu这个工具链。

不过这种与本地路径紧耦合的配置方案并不是适合大范围协作,无法提交到git仓库中分享给其他人。

Rust还提供了另外一种override toolchain版本的方法,我们可以在hellorust项目的根目录下放置一个名为rust-toolchain.toml的文件,其内容如下:

// rust-toolchain.toml

[toolchain]
channel = "1.66.0"

我们先执行rustup override unset将上面设置的override规则取消掉:

$rustup override unset
info: override toolchain for '/root/test/rust/hellorust' removed

然后toolchain.toml就会生效了:

// 在hellorust路径下
$rustc -V
rustc 1.66.0 (69f9c33d7 2022-12-12)

显然,这里涉及到了override的优先级顺序问题。Rust规定版本override的优先级顺序由高到低依次是:

  1. plus语法:“rustc +1.66.0 -V”
  2. RUSTUP_TOOLCHAIN环境变量 (default: none)
  3. rustup override命令
  4. rust-toolchain.toml
  5. 默认toolchain

2.2.1.3 在Windows上安装Rust

上述通过“curl|ssh”安装rustup,并通过rustup安装Rust工具链的方法是在Linux和macOS上安装Rust的主流方法,但在习惯于图形化安装的Windows上,略有变通。在Windows上,我们可以下载和安装一个名为rustup-init.exe的程序,它等价于其他os上的rustup,但可以交互式的引导用户安装。

由于手旁没有Windows环境,具体的安装过程这里就不详细说明了。

2.2.2 离线安装包安装

和Go一样,Rust也提供了离线安装包的安装方式,在离线安装包下载页面可以找到各个平台的多种文件格式(目前包括.tar.xz、.msi和.pkg)的离线安装包。

习惯在Windows上开发Rust程序的开发者可以直接下载和使用.msi来安装Rust开发环境。

2.3 更新和卸载Rust

使用rustup来更新和卸载Rust非常简单方便。

以更新stable版本为例,通过下面命令,我们就可以将本地的stable版本更新到最新stable版本。以我的macOS为例,我通过rustup将stable版本更新为最新的Rust 1.77.2:

$rustup update stable
info: syncing channel updates for 'stable-x86_64-apple-darwin'
info: latest update on 2024-04-09, rust version 1.77.2 (25ef9e3d8 2024-04-09)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
 14.9 MiB /  14.9 MiB (100 %)   9.3 MiB/s in  1s ETA:  0s
info: downloading component 'rust-std'
 25.4 MiB /  25.4 MiB (100 %) 764.8 KiB/s in 12s ETA:  0s
info: downloading component 'rustc'
 54.9 MiB /  54.9 MiB (100 %)   8.6 MiB/s in  7s ETA:  0s
info: downloading component 'rustfmt'
  1.8 MiB /   1.8 MiB (100 %) 564.9 KiB/s in  3s ETA:  0s
info: removing previous version of component 'cargo'
info: removing previous version of component 'clippy'
info: removing previous version of component 'rust-docs'
info: removing previous version of component 'rust-std'
info: removing previous version of component 'rustc'
info: removing previous version of component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
 14.9 MiB /  14.9 MiB (100 %)   4.2 MiB/s in  3s ETA:  0s
info: installing component 'rust-std'
 25.4 MiB /  25.4 MiB (100 %)  13.8 MiB/s in  2s ETA:  0s
info: installing component 'rustc'
 54.9 MiB /  54.9 MiB (100 %)  13.9 MiB/s in  4s ETA:  0s
info: installing component 'rustfmt'

  stable-x86_64-apple-darwin updated - rustc 1.77.2 (25ef9e3d8 2024-04-09) (from rustc 1.75.0 (82e1608df 2023-12-21))
... ...

通过更新的日志,我们看到rust的相关工具组件(比如cargo、rustfmt等)也得到了一并的更新。

Rust通过rustup提供了卸载Rust环境的命令:

$rustup self uninstall

Thanks for hacking in Rust!

This will uninstall all Rust toolchains and data, and remove
$HOME/.cargo/bin from your PATH environment variable.

Continue? (y/N) _

我们看到:rustup会在控制台上与你进行一个确认继续的交互,确认你真的要卸载。如果你输入y并按Enter键继续,那么rustup会移除所有与Rust相关的文件,包括工具链、库、环境变量等。

如果你需要保留一些Rust版本,可以先运行rustup toolchain list,查看已安装的版本。然后用rustup toolchain uninstall命令单独卸载不需要的版本:

$rustup toolchain uninstall 1.64-x86_64-apple-darwin
info: uninstalling toolchain '1.64-x86_64-apple-darwin'
info: toolchain '1.64-x86_64-apple-darwin' uninstalled

2.4 配置Rust

《Go语言第一课专栏》讲解安装Go之后的配置时,我们主要提到了国内开发者要配置一个合适的GOPROXY。而Rust的各个站点都在合规访问范围内,我们安装Rust后无需做任何配置即可敞开使用Rust。

不过也有开发者觉得通过Rust官方下载crate慢,希望更换国内源,这种换源主要涉及的是cargo这个工具,我们后续学习Cargo时再来说明如何换源以及换哪个稳定的国内源。

2.5 在线体验Rust

Go提供了在线的Go playground可供尚未在本地安装Go环境的开发者体验Go语法,Go playground提供了三个版本:最新稳定版、次新稳定版以及tip版本,并且可以将代码通过短连接分享给其他开发者,十分方便。

这方面Rust也不逞多让,提供了功能足够丰富的Rust Playground

在这里,我们可以选择Rust的版本:stable、beta还是nightly;可以选择编译模式,是debug还是release;可以选择Rust edition;可以选择执行一些工具,比如rustfmt;可以选择执行的命令:Run、Build、Test、MIR等。

不过,Rust、Go的playground毕竟只是用于在线体验的站点,他们具有共同的一些局限,比如:不支持第三方依赖,无法做复杂的多源文件项目的体验。

2.6 编辑器与IDE

对于开发人员来说,一门语言的开发环境不仅包含语言官方提供的编译器以及其他工具链,代码编辑器或IDE也是必不可少的。接下来,我们就来简单说说使用什么编辑器或IDE来开发Rust代码。

2023年Rust官方年度的用户调查显示,在编辑器/IDE使用排名中VSCode和VIM位列前二:

Jetbrain推出的商业版RustRover位居第三,正在迎头赶上,但由于是商业版,这里就不详细介绍了。下面我们分别介绍一下如何使用VSCode和VIM来开发Rust代码,都需要安装哪些插件。

2.6.1 使用VSCode开发Rust

使用上面介绍的rustup在本地安装Rust环境后,rust的相关工具(cargo、rustc、rustfmt、rust-analyzer等)就都已经就绪!使用VSCode开发Rust只需再安装一个扩展插件即可,它就是由Rust官方维护的rust-analyzer

该插件实现了Rust语言的Language Server Protocol,可以在开发者编写Rust代码时,提供代码补全、转到定义/实现/类型定义、查找所有引用、工作区符号搜索、符号重命名、悬停时的类型和文档、类型和参数名称的嵌入提示、语义语法高亮等功能。可以说,有了Rust-analyzer的帮助,开发者可以自由在Rust代码中徜徉了。

更详细的VSCode支持Rust开发的文档,可以参考Rust in Visual Studio Code

2.6.2 使用VIM开发Rust

和VSCode仅需安装一个扩展插件相比,VIM的配置就相对复杂一些了。目前Rust+VIM的主流方案是rust.vim + coc.nvim + coc-rust-analyzer

我们以安装了vim-plug插件管理器的VIM为例,下面是VIM的插件关系以及插件与Rust工具链的交互图:

首先,通过vim-plug安装coc.nvim和rust.vim,我们需要在~/.vimrc中添加下面代码:

call plug#begin()
Plug 'neoclide/coc.nvim', {'branch': 'release'}
Plug 'rust-lang/rust.vim' "for rust
call plug#end()

然后在vim中执行:PlugInstall安装coc.nvim和rust.vim。

rust.vim是Rust团队官方维护的vim插件,用于提供Rust文件检测、语法高亮显示、代码格式化等,它需要Vim 8或更高版本才能实现完整功能。

coc.nvim则是一个强大的Neovim (Vim的衍生版本)插件,主要用于提供代码补全、语法检查、代码导航等功能,支持多种编程语言。它基于微软的 Language Server Protocol (LSP),可以与各种语言服务器集成,从而为不同语言提供智能化的开发体验。

安装coc.nvim成功后,我们再在VIM中使用:CocInstall coc-rust-analyzer安装coc.nvim的插件:coc-rust-analyzer,通过该插件可以实现与LSP实现rust-analyzer的交互,从而实现代码补全、转到定义/实现/类型定义、查找所有引用等功能。

此外,我们还需要配置一下coc.nvim,配置文件在~/.vim/coc-settings.json中:

{
    "languageserver" : {
            "rust": {
              "command": "rust-analyzer",
              "filetypes": ["rust"],
              "rootPatterns": ["Cargo.toml"]
            }
  }
}

安装好上述插件并完成配置后,你同样可以使用VIM在Rust代码中徜徉!

2.7 小结

在这一章里,我们学习了如何建立Rust开发环境。

首先我了解到,Rust有stable(稳定版)、beta(公测版)和nightly(每晚版)三种版本渠道,发布节奏是每6周一个新的稳定版,与Go语言有所区别。对于大多数开发者来说,选择最新的稳定版是最明智的选择。

接着,我介绍了在Linux环境下使用rustup这个官方工具安装Rust的方法。rustup提供了一键安装命令,可以方便地安装不同渠道的Rust版本。

安装完成后,rustup在主机的主目录下创建了.cargo和.rustup两个目录。.cargo/bin存放了cargo、rustc等命令行工具,.rustup/toolchains则存放了安装的Rust工具链。

我们还学会了如何使用rustup在不同版本间切换,并演练了如何安装指定版本的Rust。另外,通过rustup的”plus语法”,可以在单个命令中临时使用特定的Rust版本。当然Rust提供了不止一种方法,还有rust-toolchain.toml文件、环境变量等方法,请注意这些方法的优先级顺序。

最后,我们还介绍了如何利用Rust playground在线体验Rust编码,以及Rust编码使用的两种最常使用的IDE和编辑器:VSCode和VIM,针对这两个工具,我分别介绍了Rust开发环境的配置方法。

相信大家通过本章内容,已经可以成功搭建了Rust开发环境了,这为后续的Rust编程学习打下了坚实的基础。


Gopher部落知识星球在2024年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。同时,我们也会加强代码质量和最佳实践的分享,包括如何编写简洁、可读、可测试的Go代码。此外,我们还会加强星友之间的交流和互动。欢迎大家踊跃提问,分享心得,讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落,享受coding的快乐! 欢迎大家踊跃加入!

img{512x368}
img{512x368}

img{512x368}
img{512x368}

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻) – https://gopherdaily.tonybai.com

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx
  • 微博2:https://weibo.com/u/6484441286
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • Gopher Daily归档 – https://github.com/bigwhite/gopherdaily

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

使用Ollama和Go基于文本嵌入模型实现文本向量化

本文永久链接 – https://tonybai.com/2024/05/09/text-vectorization-using-ollama-and-go-based-on-text-embedding-models

基于RAG+大模型的应用已经成为当前AI应用领域的一个热门方向。RAG(Retrieval-Augmented Generation)将检索和生成两个步骤相结合,利用外部知识库来增强生成模型的能力(如下图来自网络)。

在RAG赋能的大模型应用中,关键的一步是将文本数据向量化后存储在向量数据库中(如上图的红框),以实现快速的相似度搜索,从而检索与输入查询相关的文本片段,再将检索到的文本输入给生成模型生成最终结果。

本文是我学习开发大模型应用的一篇小记,探讨的是如何使用Ollama和Go语言实现文本数据的向量化处理,这是开发基于RAG的大模型应用的前提和基础。

要进行文本向量化,我们首先要了解一下文本向量化的方法以及发展。

纵观文本向量化技术的发展历程,我们可以看到从早期的词袋模型(Bag-of-Words)、主题模型(Topic Models),到词嵌入(Word Embedding)、句嵌入(Sentence Embedding),再到当前基于预训练的文本嵌入模型(Pretrained Text Embedding Models),文本向量化的方法不断演进,语义表达能力也越来越强。

但传统的词袋模型忽略了词序和语义,主题模型又难以捕捉词间的细粒度关系,词嵌入模型(如Word2Vec、GloVe)虽然考虑了词的上下文,但无法很好地表征整个句子或文档的语义。近年来,随着预训练语言模型(如BERT、GPT等)的崛起,出现了一系列强大的文本嵌入模型,它们在大规模语料上进行预训练,能够生成高质量的句子/文档嵌入向量,广泛应用于各类NLP任务中。下图是抱抱脸(https://huggingface.co/)的最新文本嵌入模型的排行榜

目前,基于大型预训练语言模型的文本嵌入已成为主流方法。这些模型在大规模无监督语料上预训练,学习到丰富的语义知识,生成的文本嵌入能较好地编码词语、短语和句子等多个层面的语义关系。Nomic AI等组织发布了多种优秀的预训练文本嵌入模型,应用效果获得了较大提升。这种基于预训练的文本嵌入模型来实现文本数据向量化的方法也缓解了Go语言生态中文本向量化的相关库相对较少的尴尬,Gopher可以在预训练文本嵌入模型的帮助下将文本向量化。接下来,我们就来看看如何基于Ollama和Go基于文本嵌入模型实现文本向量化。

考虑到实验环境资源有限,以及Ollama对Text Embedding模型的支持,这里我选择了Nomic AI开源发布的nomic-embed-text v1.5模型,虽然在抱抱脸上它的排名并不十分靠前。

在《使用Ollama和OpenWebUI在CPU上玩转Meta Llama3-8B》一文中,我已经粗略介绍过Ollama在本地运行大模型的基本步骤,如果你对Ollama的操作还不是很了解,可以先阅读一下那篇文章。

下面我们就用ollama下载nomic-embed-text:v1.5模型:

$ollama pull nomic-embed-text:v1.5
pulling manifest
pulling manifest
pulling 970aa74c0a90... 100% ▕██████████████████████████████████████████████████████████████████▏ 274 MB
pulling c71d239df917... 100% ▕██████████████████████████████████████████████████████████████████▏  11 KB
pulling ce4a164fc046... 100% ▕██████████████████████████████████████████████████████████████████▏   17 B
pulling 31df23ea7daa... 100% ▕██████████████████████████████████████████████████████████████████▏  420 B
verifying sha256 digest
writing manifest
removing any unused layers
success

算上之前的Llama3模型,目前本地已经有了两个模型:

$ollama list
NAME                       ID              SIZE      MODIFIED
llama3:latest              71a106a91016    4.7 GB    2 weeks ago
nomic-embed-text:v1.5      0a109f422b47    274 MB    3 seconds ago

不过与llama3的对话模型不同,nomic-embed-text:v1.5是用于本文嵌入的模型,我们不能使用命令行来run该模型并通过命令行与其交互:

$ollama run nomic-embed-text:v1.5
Error: embedding models do not support chat

一旦模型下载成功,我们就可以通过Ollama的HTTP API来访问该模型了,下面是通过curl将一段文本向量化的命令:

$curl http://localhost:11434/api/embeddings -d '{
  "model": "nomic-embed-text:v1.5",
  "prompt": "The sky is blue because of Rayleigh scattering"
}'
{"embedding":[-1.246808409690857,0.10344144701957703,0.6935597658157349,-0.6157534718513489,0.4244955778121948,-0.7677388191223145,1.4136837720870972,0.012530215084552765,0.007208258379250765,-0.858286440372467,1.02878999710083,0.6512939929962158,1.0005667209625244,1.4231345653533936,0.30222395062446594,-0.4343869090080261,-1.358498215675354,-1.0671193599700928,0.3035725951194763,-1.5876567363739014,-0.9811925888061523,-0.31766557693481445,-0.32180508971214294,0.5726669430732727,-1.4187577962875366,-0.23533311486244202,-0.3387795686721802,0.02435961365699768,-0.9517765641212463,0.4120883047580719,-0.4619484841823578,-0.6658303737640381,0.010240706615149975,0.7687620520591736,0.9147310853004456,-0.18446297943592072,1.6336615085601807,1.006791353225708,-0.7928107976913452,0.3333768844604492,-0.9133707880973816,-0.8000166416168213,-0.41302260756492615,0.32945334911346436,0.44106146693229675,-1.3581880331039429,-0.2830675542354584,-0.49363842606544495,0.20744864642620087,0.039297714829444885,-0.6562637686729431,-0.24374787509441376,-0.22294744849205017,-0.664574921131134,0.5489196181297302,1.0000559091567993,0.45487216114997864,0.5257866382598877,0.25838619470596313,0.8648120760917664,0.32076674699783325,1.79911208152771,-0.23030932247638702,0.27912014722824097,0.6304138898849487,-1.1762936115264893,0.2685599625110626,-0.6646256446838379,0.332780659198761,0.1742674708366394,-0.27117523550987244,-1.1485087871551514,0.07291799038648605,0.7712352275848389,...,]}

注意:如果curl请求得到的应答是类似{“error”:”error starting the external llama server: exec: \”ollama_llama_server\”: executable file not found in $PATH “},可以尝试重启Ollama服务来解决:systemctl restart ollama。

Ollama没有提供sdk,我们就基于langchaingo的ollama包访问ollama本地加载的nomic-embed-text:v1.5模型,实现文本的向量化。下面是示例的源码:

// textembedding.go
package main

import (
        "context"
        "fmt"
        "log"

        "github.com/tmc/langchaingo/llms/ollama"
)

func main() {
        llm, err := ollama.New(ollama.WithModel("nomic-embed-text:v1.5"))
        if err != nil {
                log.Fatal(err)
        }
        ctx := context.Background()
        inputText := "The sky is blue because of Rayleigh scattering"
        result, err := llm.CreateEmbedding(ctx, []string{inputText})
        if err != nil {
                log.Fatal(err)
        }

        fmt.Printf("%#v\n", result)
        fmt.Printf("%d\n", len(result[0]))
}

更新一下依赖:

# go mod tidy
go: finding module for package github.com/tmc/langchaingo/llms/ollama
go: toolchain upgrade needed to resolve github.com/tmc/langchaingo/llms/ollama
go: github.com/tmc/langchaingo@v0.1.9 requires go >= 1.22.0; switching to go1.22.3
go: downloading go1.22.3 (linux/amd64)
go: finding module for package github.com/tmc/langchaingo/llms/ollama
go: found github.com/tmc/langchaingo/llms/ollama in github.com/tmc/langchaingo v0.1.9
go: downloading github.com/stretchr/testify v1.9.0
go: downloading github.com/pkoukk/tiktoken-go v0.1.6
go: downloading gopkg.in/yaml.v3 v3.0.1
go: downloading github.com/davecgh/go-spew v1.1.1
go: downloading github.com/pmezard/go-difflib v1.0.0
go: downloading github.com/google/uuid v1.6.0
go: downloading github.com/dlclark/regexp2 v1.10.0

我本地的Go是1.21.4版本,但langchaingo需要1.22.0版本及以上,这里考虑向前兼容性,go下载了go1.22.3。

接下来运行一下上述程序:

$go run textembedding.go
[][]float32{[]float32{-1.2468084, 0.10344145, 0.69355977, -0.6157535, 0.42449558, -0.7677388, 1.4136838, 0.012530215, 0.0072082584, -0.85828644, 1.02879, 0.651294, 1.0005667, 1.4231346, 0.30222395, -0.4343869, -1.3584982, -1.0671194, 0.3035726, -1.5876567, -0.9811926, -0.31766558, -0.3218051, 0.57266694, -1.4187578, -0.23533311, -0.33877957, 0.024359614, -0.95177656, 0.4120883, -0.46194848, -0.6658304, 0.010240707, 0.76876205, 0.9147311, -0.18446298, 1.6336615, 1.0067914, -0.7928108, 0.33337688, -0.9133708, -0.80001664, -0.4130226, 0.32945335, 0.44106147, -1.358188, -0.28306755, -0.49363843, 0.20744865, 0.039297715, -0.65626377, -0.24374788, -0.22294745, -0.6645749, 0.5489196, 1.0000559, 0.45487216, 0.52578664, 0.2583862, 0.8648121, 0.32076675, 1.7991121, -0.23030932, 0.27912015, 0.6304139, -1.1762936, 0.26855996, -0.66462564, 0.33278066, 0.17426747, -0.27117524, -1.1485088, 0.07291799, 0.7712352, -1.2570909, -0.6230442, 0.02963586, -0.4936177, -0.014295651, 0.5730515, ... ,  -0.5260737, -0.44808808, 0.9352375}}
768

我们看到输入的文本成功地被向量化了,我们输出了这个向量的维度:768。

注:文本向量维度的常见的值有200、300、768、1536等。

我们看到,基于Ollama加载的预训练文本嵌入模型,我们可以在Go语言中实现高效优质的文本向量化。将文本数据映射到语义向量空间,为基于RAG的知识库应用打下坚实的基础。有了向量后,我们便可以将其存储在向量数据库中备用,在后续的文章中,我会探讨向量数据库写入与检索的实现方法。


Gopher部落知识星球在2024年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。同时,我们也会加强代码质量和最佳实践的分享,包括如何编写简洁、可读、可测试的Go代码。此外,我们还会加强星友之间的交流和互动。欢迎大家踊跃提问,分享心得,讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落,享受coding的快乐! 欢迎大家踊跃加入!

img{512x368}
img{512x368}

img{512x368}
img{512x368}

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻) – https://gopherdaily.tonybai.com

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx
  • 微博2:https://weibo.com/u/6484441286
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • Gopher Daily归档 – https://github.com/bigwhite/gopherdaily

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats