add cargo使用指南

pull/434/head
sunface 3 years ago
parent 13d35c6cc3
commit 64246fdcc6

@ -124,6 +124,19 @@
- [优雅的关闭](tokio/graceful-shutdown.md)
- [异步跟同步共存](tokio/bridging-with-sync.md)
- [Cargo使用指南](cargo/intro.md)
- [上手使用](cargo/getting-started.md)
- [使用手册 doing](cargo/guide/intro.md)
- [为何会有Cargo](cargo/guide/why-exist.md)
- [下载并构建Package](cargo/guide/download-package.md)
- [添加依赖](cargo/guide/dependencies.md)
- [Package目录结构](cargo/guide/package-layout.md)
- [进阶参考 todo](cargo/reference/intro.md)
- [指定依赖项 todo](cargo/reference/specify-deps/intro.md)
- [依赖覆盖 todo](cargo/reference/specify-deps/overriding.md)
- [Cargo.toml格式讲解 todo](cargo/reference/manifest/intro.md)
- [修改默认的文件目录 todo](cargo/reference/manifest/cargo-target.md)
- [易混淆概念解析](confonding/intro.md)
- [切片和切片引用](confonding/slice.md)
- [String、&str 和 str](confonding/string.md)
@ -158,25 +171,12 @@
- [Rust最佳实践 doing](practice/intro.md)
- [日常开发三方库精选](practice/third-party-libs.md)
- [代码开发实践 todo](practice/best-pratice.md)
- [命名规范](practice/naming.md)
- [日志 todo](practice/logs.md)
- [代码开发实践 todo](practice/best-pratice.md)
- [日志记录 todo](practice/logs.md)
- [可观测性监控 todo](practice/observability.md)
- [如何实现一个链表 todo]()
- [Cargo使用指南 todo](cargo/intro.md)
- [常用命令 todo](cargo/commands.md)
- [项目结构 todo](cargo/layout.md)
- [Cargo.toml和Cargo.lock todo](cargo/cargo-toml-lock.md)
- [依赖管理 todo](cargo/dependency.md)
- [构建缓存 todo](cargo/cache.md)
- [版本管理 todo](cargo/version.md)
- [工作空间 todo](cargo/workspace.md)
- [条件编译、条件依赖 todo](cargo/feature.md)
- [配置参数 todo](cargo/manifest.md)
- [自定义构建脚本 todo](cargo/build-js.md)
- [Cargo profile todo](cargo/profile.md)
<!-- - [如何实现一个链表 todo]() -->
- [Rust性能剖析 todo](profiling/intro.md)
- [深入内存 todo](profiling/memory/intro.md)

@ -1 +0,0 @@
# 自定义构建脚本

@ -1,7 +0,0 @@
# 构建缓存
## cargo 下载卡住
删除 ~/.cargo/.package-cache
https://zhuanlan.zhihu.com/p/74875840

@ -1 +0,0 @@
# Cargo.toml和Cargo.lock

@ -1 +0,0 @@
# 常用命令

@ -1,6 +0,0 @@
# 依赖管理
## 依赖升级
Minor note about your second point: You can use cargo update to update versions of transitive dependencies in your Cargo.lock when applicable; the very nice cargo-edit crate provides a cargo upgrade command which does the same for your Cargo.toml. If you use VSCode, I can also recommend the "crates" extension which shows available updates inline in your Cargo.toml.

@ -1,23 +0,0 @@
# 条件编译、条件依赖
## 通过featre来实现不同的derive
比如有一个类型,我们希望在不同包引用它的时候,派生引用不同的特征,可以这么做:
在`Cargo.toml`中定义新的`feature`:
```toml
[features]
sqlx = []
```
在类型定义处:
```rust
#[cfg_attr(feature = "sqlx", derive(sqlx::Type)]
#[derive(Debug, PartialEq, Deserialize, Serialize, strum_macros::EnumString)]
pub enum Role {Owner,Admin,User,}
```
在希望派生`sqlx`的包:
```toml
your_shared_crate = { version = "0.0.1", features = ["sqlx"] }
```

@ -0,0 +1,71 @@
# 上手使用
Cargo 会在安装 Rust 的时候一并进行安装,无需我们手动的操作执行,安装 Rust 参见[这里](https://course.rs/first-try/installation.html)。
在开始之前,先来明确一个名词: `Package`,由于 `Crate` 被翻译成包,因此 `Package` 再被翻译成包就很不合适。为此我们决定不对 `Package` 进行翻译,但是大家可以将其理解为软件包、项目或工程。
安装完成后,接下来使用 `Cargo` 来创建一个新的[二进制 Package](https://course.rs/basic/crate-module/crate.html),二进制意味着该 `Package` 可以作为一个服务运行或被编译成可执行文件运行。
```rust
$ cargo new hello_world
```
这里我们使用 `cargo new` 创建一个新的 Package ,事实上该命令等价于 `cargo new hello_world --bin``bin` 是 `binary` 的简写,代表着二进制程序,由于 `--bin` 是默认参数,因此可以对其进行省略。
创建成功后,先来看看 `Package` 的目录结构长啥样:
```shell
$ cd hello_world
$ tree .
.
├── Cargo.toml
└── src
└── main.rs
1 directory, 2 files
```
这里有一个很显眼的文件 `Cargo.toml`,一看就知道它是 `Cargo` 使用的配置文件,这个关系类似于: `package.json``npm` 的配置文件。
```toml
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
[dependencies]
```
以上就是 `Cargo.toml` 的全部内容,它被称之为清单( manifest ),包含了 `Cargo` 编译程序所需的所有元数据。
下面是 `src/main.rs` 的内容
```rust
fn main() {
println!("Hello, world!");
}
```
可以看出 `Cargo` 还为我们自动生成了一个 `hello world` 程序,或者说[二进制包](https://course.rs/basic/crate-module/crate.html),对程序进行编译构建:
```shell
$ cargo build
Compiling hello_world v0.1.0 (file:///path/to/package/hello_world)
```
然后再运行编译出的二进制可执行文件:
```shell
$ ./target/debug/hello_world
Hello, world!
```
注意到路径中的 `debug` 了吗?它说明我们刚才的编译是 `Debug` 模式,该模式主要用于测试目的,如果想要进行生产编译,我们需要使用 `Release` 模式 `cargo build --release`,然后通过 `./target/release/hello_world` 运行。
除了上面的编译 + 运行方式外,在日常开发中,我们还可以使用一个简单的命令直接运行:
```shell
$ cargo run
Fresh hello_world v0.1.0 (file:///path/to/package/hello_world)
Running `target/hello_world`
Hello, world!
```
`cargo run` 会帮我们自动完成编译、运行的过程,当然,该命令也支持 `Release` 模式: `cargo run --release`
> 如果你的程序在跑性能测试 benchmark一定要使用 `Relase` 模式,因为该模式下,程序会做大量性能优化
在快速了解 `Cargo` 的使用方式后,下面,我们将正式进入 Cargo 的学习之旅。

@ -0,0 +1,60 @@
# 添加依赖
[`crates.io`](https://crates.io) 是 Rust 社区维护的中心化 `package` 注册服务,用户可以在其中寻找和下载所需的 `package`。对于 `cargo` 来说,默认就是从这里下载依赖。
下面我们来添加一个 `time` 依赖包,若你的 `Cargo.toml` 文件中没有 `[dependencies]` 部分,就手动添加一个,然后添加目标包名和版本号:
```toml
[dependencies]
time = "0.1.12"
```
可以看到我们指定了 `time` 包的版本号 "0.1.12",关于版本号,实际上还有其它的指定方式,具体参见[指定依赖项](https://course.rs/cargo/reference/specify-deps/intro.html)章节。
如果想继续添加 `regexp` 包,只需在 `time` 包后面添加即可 :
```toml
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
[dependencies]
time = "0.1.12"
regex = "0.1.41"
```
此时,再通过运行 `cargo build` 来重新构建,首先 `Cargo` 会获取新的依赖以及依赖的依赖, 接着对它们进行编译并更新 `Cargo.lock`:
```shell
$ cargo build
Updating crates.io index
Downloading memchr v0.1.5
Downloading libc v0.1.10
Downloading regex-syntax v0.2.1
Downloading memchr v0.1.5
Downloading aho-corasick v0.3.0
Downloading regex v0.1.41
Compiling memchr v0.1.5
Compiling libc v0.1.10
Compiling regex-syntax v0.2.1
Compiling memchr v0.1.5
Compiling aho-corasick v0.3.0
Compiling regex v0.1.41
Compiling hello_world v0.1.0 (file:///path/to/package/hello_world)
```
`Cargo.lock` 中包含了我们项目使用的所有依赖的准确版本信息。这个非常重要,未来就算 `regexp` 的作者升级了该包,我们依然会下载 `Cargo.lock` 中的版本,而不是最新的版本,只有这样,才能保证项目依赖包不会莫名其妙的因为更新升级导致无法编译。 当然,你还可以使用 `cargo update` 来手动更新包的版本。
此时,就可以在 `src/main.rs` 中使用新引入的 `regexp` 包:
```rust
use regex::Regex;
fn main() {
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
println!("Did our date match? {}", re.is_match("2014-01-01"));
}
```
运行后输出:
```shell
$ cargo run
Running `target/hello_world`
Did our date match? true
```

@ -0,0 +1,17 @@
# 下载并构建Package
如果看中 `Github` 上的某个开源 Rust 项目,那下载并构建它将是非常简单的。
```shell
$ git clone https://github.com/rust-lang/regex.git
$ cd regex
```
如上所示,直接从 `github` 上克隆下来想要的项目,然后使用 `cargo build` 进行构建即可:
```shell
$ cargo build
Compiling regex v1.5.0 (file:///path/to/package/regex)
```
该命令将下载相关的依赖库,等下载成功后,再对 `package` 和下载的依赖进行一同的编译构建。
这就是包管理工具的强大之处,`cargo build` 搞定一切,而背后隐藏的复杂配置、参数你都无需关心。

@ -0,0 +1,2 @@
# 使用手册
在本章中,我们将学习 `Cargo` 的详细使用方式,例如 `Package` 的创建与管理、依赖拉取、`Package` 结构描述等。

@ -0,0 +1,47 @@
# 标准的Package目录结构
一个典型的 `Package` 目录结构如下:
```shell
.
├── Cargo.lock
├── Cargo.toml
├── src/
│ ├── lib.rs
│ ├── main.rs
│ └── bin/
│ ├── named-executable.rs
│ ├── another-executable.rs
│ └── multi-file-executable/
│ ├── main.rs
│ └── some_module.rs
├── benches/
│ ├── large-input.rs
│ └── multi-file-bench/
│ ├── main.rs
│ └── bench_module.rs
├── examples/
│ ├── simple.rs
│ └── multi-file-example/
│ ├── main.rs
│ └── ex_module.rs
└── tests/
├── some-integration-tests.rs
└── multi-file-test/
├── main.rs
└── test_module.rs
```
这也是 `Cargo` 推荐的目录结构,解释如下:
- `Cargo.toml``Cargo.lock` 保存在 `package` 根目录下
- 源代码放在 `src` 目录下
- 默认的 `lib` 包根是 `src/lib.rs`
- 默认的二进制包根是 `src/main.rs`
- 其它二进制包根放在 `src/bin/` 目录下
- 基准测试 benchmark 放在 `benches` 目录下
- 示例代码放在 `examples` 目录下
- 集成测试代码放在 `tests` 目录下
关于 Rust 中的包和模块,[之前的章节](https://course.rs/basic/crate-module/intro.html)有更详细的解释。
这里的一些目录配置还能通过配置文件来修改,详情参见本章的后续章节[修改默认的文件目录](https://course.rs/cargo/reference/manifest/cargo-target.html)

@ -0,0 +1,32 @@
# 为何会有Cargo
根据之前学习的知识Rust 有两种类型的包: `lib` 包和二进制包,前者是俗称的依赖包,用于被其它包所引入,而后者是一个应用服务,可以编译成二进制可执行文件进行运行。
包是通过 Rust 编译器 `rustc` 进行编译的:
```rust
$ rustc hello.rs
$ ./hello
Hello, world!
```
上面我们直接使用 `rustc` 对二进制包 `hello.rs` 进行编译,生成二进制可执行文件 `hello`,并对其进行运行。
上面的方式虽然简单,但是有几个问题:
- 必须要指定文件名编译,当 package 复杂后,这种编译方式也随之更加复杂
- 如果要指定编译参数,情况将更加复杂
最关键的是,外部依赖库的引入也将是一个大问题。大部分实际的项目都有不少依赖包,而这些依赖包又间接的依赖了新的依赖包,在这种复杂情况下,如何管理依赖包及其版本也成为一个相当棘手的问题。
正是因为这些原因,与其使用 `rustc` ,我们可以使用一个强大的包管理工具来解决问题:欢迎 `Cargo` 闪亮登场。
## Cargo
`Cargo` 解决了之前描述的所有问题,同时它保证了每次重复的构建都不会改变上一次构建的结果,这背后是通过完善且强大的依赖包版本管理来实现的。
总之,`Cargo` 为了实现目标,做了四件事:
- 引入两个元数据文件,包含 `package` 的方方面面信息: `Cargo.toml``Cargo.lock`
- 获取和构建 `package` 的依赖,例如 `Cargo.toml` 中的依赖包版本描述,以及从 `crates.io` 下载包
- 调用 `rustc` (或其它编译器) 并使用的正确的参数来构建 `package`,例如 `cargo build`
- 引入一些惯例,让 `package` 的使用更加简单
毫不夸张的说,得益于 `Cargo` 的标准化,只要你使用它构建过一个项目,那构建其它使用 `Cargo` 的项目,也将不存在任何困难。

@ -1,2 +1,8 @@
# cargo
# Cargo 使用指南
Rust 语言的名气之所以这么大,保守估计 `Cargo` 的贡献就占了三分之一。
`Cargo` 是包管理工具,可以用于依赖包的下载、编译、更新、分发等,与 `Cargo` 一样有名的还有 [`crates.io`](https://crates.io),它是社区提供的包注册中心:用户可以将自己的包发布到该注册中心,然后其它用户通过注册中心引入该包。
> 本章内容是基于 [Cargo Book](https://doc.rust-lang.org/stable/cargo/index.html) 翻译,并做了一些内容优化和目录组织上的调整
<img src="https://doc.rust-lang.org/stable/cargo/images/Cargo-Logo-Small.png" />

@ -1,6 +0,0 @@
# 项目结构
## main函数的正确位置
目前发现部分人会搞不懂main函数应该放在哪个文件中结果导致编译器报错找不到main函数

@ -1,4 +0,0 @@
# Cargo profile
## custom profiles (rust 1.57.0)

@ -0,0 +1 @@
# 修改默认的文件目录

@ -0,0 +1 @@
# Cargo.toml格式讲解

@ -1,4 +0,0 @@
# 版本管理
Rust允许同一个包的多个API不兼容的版本共存因此会导致问题https://www.reddit.com/r/rust/comments/rlil11/simple_crud_web_api_with_actix_getting_error/

@ -1 +0,0 @@
# 工作空间
Loading…
Cancel
Save