Rust 学习笔记:发布一个 crate 到 crates.io
Rust 学习笔记:发布一个 crate 到 crates.io
- Rust 学习笔记:发布一个 crate 到 crates.io
- 提供有用的文档注释
- 常用标题
- 文档注释作为测试
- 注释所包含的项目
- 使用 pub use 导出一个方便的公共 API
- 设置 crates.io 账户
- 添加 metadata 到一个新的 crate
- 发布到 crates.io
- 发布现有 crate 的新版本
- 使用 cargo yank 在 crates.io 上废弃 crate 特定的版本
Rust 学习笔记:发布一个 crate 到 crates.io
我们已经使用过来自 crates.io 的包作为我们项目的依赖项,但是你也可以通过发布你自己的包与其他人共享你的代码。在 crates.io 上的 crate 注册表分发包的源代码,因此它主要托管开源代码。
Rust 和 Cargo 的特性使得发布的包更容易被人们找到和使用。接下来我们将讨论其中的一些特性,然后解释如何发布一个包。
提供有用的文档注释
之前我们讨论了如何使用两个斜杠 // 注释 Rust 代码。
Rust 还为文档提供了一种特殊的注释,方便地称为文档注释,它将生成 HTML 文档,其中显示了公共 API 项的文档注释内容。
文档注释使用三个斜杠 ///,,并支持 Markdown 符号来格式化文本。将文档注释放在他们要记录的项目的前面。
下面代码显示了一个名为 my_crate 的 crate 中的 add_one 函数的文档注释。
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {x + 1
}
在这里,我们将描述 add_one 函数的作用,以 Examples 开头的一节,然后提供演示如何使用 add_one 函数的代码。我们可以通过运行 cargo doc 从这个文档注释生成 HTML 文档。该命令运行随 Rust 分发的 rustdoc 工具,并将生成的 HTML 文档放在 target/doc 目录中。
为方便起见,运行 cargo doc --open 将为当前 crate 的文档(以及所有 crate 依赖项的文档)构建 HTML,并在 web 浏览器中打开结果。
在打开的文档中导航到 add_one 函数:
常用标题
我们使用 # Examples
Markdown 标题在 HTML 中创建了一个标题为 “Examples” 的部分。以下是 crate 作者在他们的文档中经常使用的其他 Markdown 标题:
-
Panics:被记录的功能可能出现恐 panic 的场景。如果函数的调用者不希望他们的程序出现 panic,那么他们应该确保在这些情况下不调用该函数。
-
Errors:如果函数返回一个 Result,描述可能发生的错误类型以及可能导致这些错误返回的条件可能对调用者有帮助,以便他们可以编写代码以不同的方式处理不同类型的错误。
-
Safety:如果函数调用是不安全的,应该有一节解释为什么函数是不安全的,并涵盖函数期望调用者维护的不变量。
大多数文档注释不需要所有这些部分,但这是一个很好的清单,可以提醒代码的用户感兴趣的方面。
文档注释作为测试
在文档注释中添加示例代码块可以帮助演示如何使用库,这样做还有一个额外的好处:运行 cargo test 将把文档中的代码示例作为测试运行。
如果我们使用 add_one 函数的文档运行 cargo test,我们将在测试结果中看到如下所示的部分:
Doc-tests my_craterunning 1 test
test src/lib.rs - add_one (line 5) ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s
如果我们更改函数或示例,使示例中的 assert_eq! 出现异常并再次运行 cargo test,我们将看到文档测试捕捉到示例和代码彼此不同步。
注释所包含的项目
注释 //! 将为包含它的项(crate 或者模块)添加文档,而不是单个函数。我们通常在 crate 根文件(按照惯例是 src/lib.js)或模块中使用这些文档注释来作为一个整体记录 crate 或模块。
例如,为了添加描述包含 add_one 函数的 my_crate 这一 crate 用途的文档,我们添加以 //! 开头的文档注释到 src/lib.rs 文件的开头。
//! # My Crate
//!
//! `my_crate` is a collection of utilities to make performing certain
//! calculations more convenient./// Adds one to the number given.
// --snip--
以 //! 注释的这些行描述了整个 crate。
当我们运行 cargo doc --open 时,这些注释将显示在 my_crate 文档的首页上,位于 crate 中的公共项目列表上方:
项目中的文档注释对于描述 crate 和模块尤其有用。使用它们来解释 crate 的总体目的,以帮助用户理解 crate 的组织结构。
使用 pub use 导出一个方便的公共 API
发布 crate 时,公共 API 的结构是一个主要考虑因素。如果你的 crate 有一个大的模块层次结构,使用者可能很难找到他们想要使用的部分。
结构层次太多会影响使用。用户可能还会因为必须输入 use my_crate::some_module::another_module::UsefulType;
而不是使用 use my_crate::UsefulType;
。
之前我们介绍了如何使用 pub 关键字将项设为公共,以及如何使用 use 关键字将项引入作用域。如果结构不方便其他人从另一个库中使用,可以使用 pub use 重新导出项,以创建与私有结构不同的公共结构。重新导出在一个位置获取公共项,并使其在另一个位置公开,就好像它是在另一个位置定义的一样。
例如,假设我们创建了一个名为 art 的库,用于建模艺术概念。在这个库中有两个模块:一个 types 模块包含两个枚举 PrimaryColor 和 SecondaryColor,一个 utils 模块包含一个名为 mix 的函数。
//! # Art
//!
//! A library for modeling artistic concepts.pub mod kinds {/// The primary colors according to the RYB color model.pub enum PrimaryColor {Red,Yellow,Blue,}/// The secondary colors according to the RYB color model.pub enum SecondaryColor {Orange,Green,Purple,}
}pub mod utils {use crate::kinds::*;/// Combines two primary colors in equal amounts to create/// a secondary color.pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {// --snip--}
}
运行 cargo doc,生成 crate 文档:
注意,PrimaryColor 和 SecondaryColor 类型没有在首页上列出,mix 函数也没有。我们必须点击 kinds 和 utils 来查看它们。
另一个依赖于此库的 crate 则需要使用语句将 art 中的项目带入范围,并指定当前定义的模块结构。例如:
use art::kinds::PrimaryColor;
use art::utils::mix;fn main() {let red = PrimaryColor::Red;let yellow = PrimaryColor::Yellow;mix(red, yellow);
}
使用 art crate 的开发者必须弄清楚 PrimaryColor 在 kinds 模块中,mix 在 utils 模块中。然而,内部结构并不包含任何有用的信息,只会徒增麻烦。
为了从公共 API 中移除内部组织,我们可以修改 art crate 中的代码,添加 pub use 语句来重新导出顶层的项目:
//! # Art
//!
//! A library for modeling artistic concepts.pub use self::kinds::PrimaryColor;
pub use self::kinds::SecondaryColor;
pub use self::utils::mix;pub mod kinds {// --snip--
}pub mod utils {// --snip--
}
cargo doc 为这个 crate 生成的 API 文档现在将在首页列出和链接重新导出(re-exports)的条目,使得 PrimaryColor 和 SecondaryColor 类型以及 mix 函数更容易找到。
这样一来,使用者可以使用更方便的导入语句:
use art::PrimaryColor;
use art::mix;fn main() {// --snip--
}
在有许多嵌套模块的情况下,使用 pub 在顶层重新导出类型可以对使用 crate 的人的体验产生重大影响。pub 用法的另一种常见用法是重新导出当前 crate 中依赖项的定义,使该 crate 的定义成为当前 crate 的公共 API 的一部分。
创建有用的公共 API 结构与其说是一门科学,不如说是一门艺术。选择 pub 可以让你在内部结构上更加灵活,并将内部结构与你呈现给用户的内容分离开来。
设置 crates.io 账户
在发布任何 crate 之前,您需要在 crates.io 上创建一个帐户并获得一个 API 令牌。要做到这一点,请访问 crates.io 的主页。登录后,访问 https://crates.io/me/ 的帐户设置并检索 API 密钥。然后运行 cargo login 命令并在提示时粘贴 API 密钥,如下所示:
$ cargo login
abcdefghijklmnopqrstuvwxyz012345
此命令将向 Cargo 告知你的 API 令牌,并将其本地存储在 ~/.cargo/credentials 中。请注意,这个令牌不要与其他人共享。
添加 metadata 到一个新的 crate
假设你有一个想要发布的 crate,在发布之前,您需要在 crate 的 Cargo.toml 的 [package] 部分中添加一些元数据。
crate 需要一个唯一的名称。当你在本地开发一个 crate 时,你可以给它起任何你喜欢的名字。然而,crates.io 上的 crate 名称按先到先得原则分配。在尝试发布 crate 之前,搜索想要使用的名称。如果使用了该名称,则需要找到另一个名称并编辑 Cargo.toml 文件 [package] 中的名称字段,如下所示:
[package]
name = "guessing_game"
即使选择了一个唯一的名称,当运行 cargo publish 来发布此时的 crate 时,还会报错:
$ cargo publishUpdating crates.io index
warning: manifest has no description, license, license-file, documentation, homepage or repository.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
--snip--
error: failed to publish to registry at https://crates.ioCaused by:the remote server responded with an error (status 400 Bad Request): missing or empty metadata fields: description, license. Please see https://doc.rust-lang.org/cargo/reference/manifest.html for more information on configuring these fields
因为遗漏了一些关键信息:需要描述和许可,以便人们知道这个 crate 是做什么的,以及他们可以在什么条件下使用它。在 Cargo.toml 中添加一到两句话的描述,因为它会和你的 crate 一起出现在搜索结果中。对于 license 字段,你需要提供一个许可证标识符值。Linux 基金会列出了可以用于此值的标识符。例如,要指定你已经使用 MIT 许可证授权了你的 crate,请添加 MIT 标识符:
[package]
name = "guessing_game"
license = "MIT"
如果希望使用 Linux 基金会中没有出现的许可证,则需要将该许可证的文本放在一个文件中,将该文件包含在项目中,然后使用 license-file 来指定该文件的名称,而不是使用许可证密钥。
Rust 社区中的许多人以与 Rust 相同的方式使用 MIT OR Apache-2.0 的双重许可来许可他们的项目。
你可以为你的项目指定用 OR 分隔的多个许可证标识符,从而拥有多个许可证。
有了唯一的名称、版本、描述,以及添加的许可证,准备发布的项目的 Cargo.toml 文件可能如下所示:
[package]
name = "guessing_game"
version = "0.1.0"
edition = "2024"
description = "A fun game where you guess what number the computer has chosen."
license = "MIT OR Apache-2.0"[dependencies]
参考文档:https://doc.rust-lang.org/cargo/
该文档描述了你可以指定的其他元数据,以确保其他人可以更轻松地发现和使用你的 crate。
发布到 crates.io
现在你已经创建了一个帐户,保存了 API 令牌,为 crate 选择了一个名称,并指定了所需的元数据,现在就可以发布了!发布一个 crate 会向 crates.io 上传一个特定的版本,供他人使用。
发布是永久性的。版本永远不能被覆盖,代码也不能被删除。creates.io 的一个主要目标是充当代码的永久存档,以便依赖于 creates.io 的 crate 的所有项目的构建将继续工作。允许版本删除将使实现这一目标变得不可能。但是,可以发布的 crate 版本数量没有限制。
再次运行 cargo publish 命令,成功了:
$ cargo publishUpdating crates.io indexPackaging guessing_game v0.1.0 (file:///projects/guessing_game)Verifying guessing_game v0.1.0 (file:///projects/guessing_game)Compiling guessing_game v0.1.0
(file:///projects/guessing_game/target/package/guessing_game-0.1.0)Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19sUploading guessing_game v0.1.0 (file:///projects/guessing_game)
现在你已经与 Rust 社区共享了你的代码,任何人都可以轻松地将你的 crate 添加为其项目的依赖项。
发布现有 crate 的新版本
对 crate 进行更改并准备发布新版本时,可以更改 Cargo 中指定的版本值。重新归档并重新发布。使用 Semantic Versioning 规则根据所做的更改类型来决定合适的下一个版本号。然后运行 cargo publish 来上传新版本。
使用 cargo yank 在 crates.io 上废弃 crate 特定的版本
虽然不能删除旧版本的 crate,但可以阻止任何未来的项目将它们添加为新的依赖项。
cargo yank 可以防止新项目依赖于该版本,同时允许所有依赖于该版本的现有项目继续进行。本质上,yank 意味着所有具有 Cargo.lock 的项目都不会中断,并且将来生成的任何 Cargo.lock 文件都不会使用被 yank 的版本。
运行 cargo yank,并指定版本:
$ cargo yank --vers 1.0.1Updating crates.io indexYank guessing_game@1.0.1
通过在命令中添加 --undo,还可以撤销一个 yank 命令,并允许项目根据版本重新启动:
$ cargo yank --vers 1.0.1 --undoUpdating crates.io indexUnyank guessing_game@1.0.1
注意,yank 并不能删除任何代码。
相关文章:

Rust 学习笔记:发布一个 crate 到 crates.io
Rust 学习笔记:发布一个 crate 到 crates.io Rust 学习笔记:发布一个 crate 到 crates.io提供有用的文档注释常用标题文档注释作为测试注释所包含的项目 使用 pub use 导出一个方便的公共 API设置 crates.io 账户添加 metadata 到一个新的 crate发布到 c…...
剪枝中的 `break` 与 `return` 区别详解
在回溯算法的剪枝操作中: if (sum candidates[i] > target) break;这个 break 既不等效于 return,也不会终止整个回溯过程。它只会终止当前层循环的后续迭代,而不会影响其他分支的回溯。让我用图解和示例详细说明: …...
Spring Boot 4.0实战:构建高并发电商系统
Spring Boot 4.0作为Java生态的全新里程碑,首次原生支持虚拟线程(Virtual Threads)与Project Loom特性,单机QPS处理能力较3.x版本提升5-8倍。本文以电商系统为实战场景,深度解析Spring Boot 4.0在微服务架构、分库分表…...

Vert.x学习笔记-EventLoop与Context的关系
Vert.x学习笔记 1. EventLoop 的核心作用2. Context 的核心作用3. EventLoop 与 Context 的关系1. 事件循环(EventLoop)的核心职责2. 上下文(Context)的核心职责3. 事件循环与上下文的关系(1)一对一绑定&am…...

2025030给荣品PRO-RK3566开发板单独升级Android13的boot.img
./build.sh init ./build.sh -K ./build.sh kernel 【导入配置文件】 Z:\Android13.0\rockdev\Image-rk3566_t\config.cfg 【更新的内核】 Z:\Android13.0\rockdev\Image-rk3566_t\boot.img 【导入分区表,使用原始的config.cfg会出错的^_】 Z:\Android13.0\rockdev\…...

由enctype-引出post与get的关系,最后深究至请求/响应报文
本篇载自我的笔记,本次为第二次复习。我觉得我有能力理一下思路了。 --- 笔记截图。 enctype HTML 表单的 enctype(Encode Type,编码类型)属性用于控制表单数据在提交到服务器时的编码方式,不同取值的详细解析如下&a…...
排序算法衍生问题
排序算法衍生问题 引言 排序算法是计算机科学中基础且重要的算法之一,其应用广泛,如数据统计分析、数据库操作、网络排序等。随着计算机科学的发展,排序算法的研究不仅局限于传统的排序方法,还衍生出许多有趣且实用的衍生问题。…...
Mac电脑上本地安装 redis并配置开启自启完整流程
文章目录 一、安装 Redis方法 1:通过源码编译安装(推荐)方法 2:通过 Homebrew 安装(可选) 二、配置 Redis1. 创建配置文件和数据目录2. 修改配置文件 三、配置开机自启1、通过 launchd 系统服务(…...
STP(生成树协议)原理与配置
冗余链路与环路问题 冗余链路虽然提供网络可靠性,但会引发环路问题。广播风暴导致网络资源耗尽,MAC地址表频繁更新造成震荡,同一数据帧通过不同路径重复传输影响数据完整性。 STP工作机制 生成树协议通过选举机制消除环路,同时…...

搭建基于VsCode的ESP32的开发环境教程
一、VsCode搜索ESP-IDF插件 根据插件处搜索找到ESP-IDF并安装 安装完成 二、配置安装ESP-IDF 配置IDF 按照如下配置,点击安装 安装完成 三、使用案例程序 创建一个闪光灯的例子程序,演示程序编译下载。 选择blink例子,闪烁LED的程序 选…...

【MFC】初识MFC
目录 01 模态和非模态对话框 02 静态文本 static text 01 模态和非模态对话框 首先我们需要知道模态对话框和非模态对话框的区别: 模态对话框是一种阻塞时对话框,它会阻止用户与应用程序的其他部分进行交互,直到用户与该对话框进行交互并关…...
C++.二分法教程
二分法 1. 问题引入1.1 猜数字游戏2.1 二分法核心思想为什么需要二分法?二分法的基本步骤示例代码代码解析 2.2 二分法适用场景有序数组查找效率要求高示例场景示例代码代码解析 3.1 初始化左右边界示例代码代码解析 3.2 计算中间值示例代码代码解析 3.3 判断与更新…...

如何通过数据分析优化项目决策
通过数据分析优化项目决策需从明确数据分析目标、选择适当的数据分析工具、确保数据质量、建立数据驱动文化等方面入手,其中,明确数据分析目标是优化决策过程的基础,只有清晰明确的数据分析目标才能指导有效的数据采集与分析,避免…...

2024年数维杯国际大学生数学建模挑战赛B题空间变量协同估计方法研究解题全过程论文及程序
2024年数维杯国际大学生数学建模挑战赛 B题 空间变量协同估计方法研究 原题再现: 在数理统计学中,简单采样通常假设来自相同总体的采样点彼此独立。与数理统计相反,空间统计假设空间变量的采样点是相依的,并在其值中表现出某些趋…...

leetcode hot100刷题日记——34.将有序数组转换为二叉搜索树
First Blood:什么是平衡二叉搜索树? 二叉搜索树(BST)的性质 左小右大:每个节点的左子树中所有节点的值都小于该节点的值,右子树中所有节点的值都大于该节点的值。 子树也是BST:左子树和右子树也…...
thinkphp 5.1 部分知识记录<一>
1、配置基础 惯例配置->应用配置->模块配置->动态配置 惯例配置:核心框架内置的配置文件,无需更改。应用配置:每个应用的全局配置文件(框架安装后会生成初始的应用配置文件),有部分配置参数仅能在应用配置文件中设置。模块配置:每个模块的配置文件(相同的配置…...
RAG:面向知识密集型自然语言处理任务的检索增强生成
摘要 大型预训练语言模型已被证明能够在其参数中存储事实性知识,并在下游自然语言处理(NLP)任务的微调中取得了最先进的结果。然而,它们访问和精准操作知识的能力仍然有限,因此在知识密集型任务中,其表现落后于针对特定任务设计的架构。此外,如何为它们的决策提供出处(…...
MVVM、MVC的区别、什么是MVVM
一、什么是MVVM (一)定义 MVVM是Model - View - ViewModel的缩写,它是一种软件架构设计模式,主要用于构建用户界面。这种模式将应用程序分为三个主要部分: Model(模型层) 它是应用程序中负责…...

网页自动化部署(webhook方法)
实现步骤: 宝塔安装宝塔WebHook 2.5插件。 github 上配置网页仓库(或可在服务器的网页根目录clone)。 配置宝塔WebHook 2.5 添加hook脚本; 编辑添加syncJC脚本; #!/bin/bash # 定义网站根目录 WEBROOT"/www…...
线性代数入门:轻松理解二阶与三阶行列式的定义与理解
前言 行列式是线性代数中一个非常基础但又极其重要的概念。它不仅是解线性方程组的利器,还在矩阵理论、向量空间、特征值等问题中扮演着关键角色。今天,我将用最通俗易懂的方式,向高中生朋友们介绍二阶和三阶行列式的基本概念和计算方法。让…...

AU6825集成音频DSP的2x32W数字型ClaSSD音频功率放大器(替代TAS5825)
1.特性 ● 输出配置 - 立体声 2.0: 2 x 32W (8Ω,24V,THD N 10%) - 立体声 2.0: 2 x 26W (8Ω,21V,THD N 1%) ● 供电电压范围 - PVDD:4.5V -26.4V - DVDD: 1.8V 或者 3.3V ● 静态功耗 - 37mA at PVDD12V ● 音频性能指标 - THDN ≤ 0.02% at 1W,1kHz - SNR ≥ 107dB (A-wei…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1商用服务体验全流程
华为云 Flexus 与 DeepSeek-V3/R1 的深度整合,构建了一套 “弹性算力 智能引擎” 的协同体系。 Flexus 系列云服务器基于柔性计算技术,通过动态资源调度(如 Flexus X 实例)实现 CPU / 内存的实时弹性分配,尤其适合大模…...
Go语言的原子操作
当我们想要对某个变量并发安全的修改,除了使用官方提供的mutex,还可以使用sync/atomic包的原子操作,它能够保证对变量的读取或修改期间不被其他的协程所影响。 Golang提供的原子操作都是非侵入式的,由标准库sync/atmoic包提供&am…...
Visual Studio 2022 插件推荐
Visual Studio 2022 插件推荐 Visual Studio 2022 (简称 VS2022) 是一款强大的 IDE,适合各类系统组件、框架和应用的开发。插件是接入 VS2022 最重要的扩展方式之一,它们可以大幅提升开发效率、优化代码质量,并提供强大的调试和分析功能。 …...
【深度学习-pytorch篇】3. 优化器实现:momentum,NAG,AdaGrad,RMSProp,Adam
Optimization Algorithms Explained 1. Beale Function 与导数函数讲解 Beale 函数是一个著名的用于测试优化算法性能的函数,其具有多个局部极值点,适合评估不同优化器的表现: def beale(x1, x2):"""Beale 函数定义&#x…...

C# NX二次开发-查找连续倒圆角面
在QQ群里有人问怎么通过一个选择一个倒圆角面来自动选中一组倒圆角面。 可以通过ufun函数 UF_MODL_ask_face_type 和 UF_MODL_ask_face_props 可判断处理选择相应的一组圆角面。 代码: Tag[] 查找连续倒圆角面(Tag faceTag) {theUf.Modl.AskFaceType(faceTag, out int typ…...

今天遇到的bug
先呈现一下BUG现象。 这主要是一个传参问题,参数一直传不过去。后来我才发现,问题所在。 我们这里用的RquestBody接收参数,所有请求的参数需要用在body体中接收,但是我们用postman,用的是字符串查询方式传参&#x…...
Go语言字符串类型详解
1. 定义字符串类型 package mainimport ("fmt");func main() {var str1 string "你好 GoLang 1"var str2 "你好 GoLang 2"str3 : "你好 GoLang 3"fmt.Printf("%v--%T\n", str1, str1)// 你好 GoLang 1--stringfmt.Printf…...

长安链智能合约命令解析(全集)
创建命令解析 ./cmc client contract user create \ --contract-namefact \ --runtime-typeWASMER \ --byte-code-path./testdata/claim-wasm-demo/rust-fact-2.0.0.wasm \ --version1.0 \ --sdk-conf-path./testdata/sdk_config.yml \ --admin-key-file-paths./testdata/cryp…...

一、OpenCV的基本操作
目录 1、OpenCV的模块 2、OpenCV的基础操作 2.1图像的IO操作 2.2绘制几何图形 2.3获取并修改图像中的像素点 2.4 获取图像的属性 2.5图像通道的拆分与合并 2.6色彩空间的改变 3、OpenCV的算数操作 3.1图像的加法 3.2图像的混合 3.3总结 1、OpenCV的模块 2、OpenCV的基…...