Rust 学习笔记:发布一个 crate 到 crates.io

article/2025/8/12 11:16:22

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 并不能删除任何代码。


http://www.hkcw.cn/article/fLsGknooGb.shtml

相关文章

大白话 Seata 分布式事务浅析,详解TCC模式

大家好,我是此林。 说到分布式事务,第一时间想到 Seata,它支持多种事务模型,比如:XA模式、AT模式、TCC模式、Saga模式(长事务)。 其中 TCC 模式是高性能分布式事务解决方案,适用于核心系统等对 性能有很高…

超标量处理器设计6-指令解码

1. 指令缓存 指令缓存本质上是一个FIFO, 它能够将指令按照程序中指定的顺序存储起来,这样指令在解码的时候,仍然可以按照程序中指定的顺序进行解码。指令缓存是超标量处理器中必须的部件,其原因有两个: 1. 每周期可以取指的个数大…

技嘉华硕微星主板BIOS开启TPM模块教程

目录 一. TPM模块安装 二. 在BIOS开启TPM功能 华硕主板(Intel平台) 华硕主板(AMD平台) 技嘉主板(Intel平台) 技嘉主板(AMD平台) 微星主板(Intel平台) …

java基础知识

ASCII码 1. next() 示例​​ 读取一个字符串(遇到空格或换行符停止) 运行示例:​​ 输入: 张三 李四 输出: 张三 // 只读取了"张三","李四"留在输入缓冲区

【解决】【亲测下载obsidian可行】打不开github.com 或者 加速访问 github

Windows系统 基本思路:通过修改IP绑定来实现加速访问 1、hosts文件目录 C:\Windows\System32\drivers\etc\hosts2、修改内容 2.1 ping github.com 在Windows的cmd页面下直接输入: ping github.comPS:这一步只是看一下,没在后…

逆向入门(1)

前言: 本篇文章面向想入门逆向的新手小白。 NSSCTF和BUUCTF是两个刷题网站,知识点下面会有对应的题,大家可以自己试着做一下 NSSCTF:https://www.nssctf.cn/problem BUUCTF:https://buuoj.cn/challenges 1.看exe模式(位数&am…

经典算法回顾之最小生成树

最小生成树(Minimum Spanning Tree,简称MST)是图论中的一个重要概念,主要用于解决加权无向图中连接所有顶点且总权重最小的树结构问题。本文对两种经典的算法即Prim算法和Kruskal算法进行回顾,并对后者的正确性给出简单…

Java八股文智能体——Agent提示词(Prompt)

这个智能体能够为正在学习Java八股文的同学提供切实帮助:不仅可以帮你优化答案表述,还能直接解答八股文相关问题——它会以面试者的视角,给出贴合求职场景的专业回答。 将以下内容发送给任何一个LLM,他会按照你提示词的内容&…

VScode编译调试debug,gpu的cuda程序,Nsight

进行下面操作的前提是,我们的环境已经能跑简单的CUDA程序了。 一、安装Nsight 二、创建launch.json文件 {"version": "0.2.0","configurations": [{"name": "CUDA C: Launch","type": "cuda-gdb…

飞牛fnNAS存储空间模式详解

目录 一、NAS的存储空间 二、多硬盘对NAS速度的提升原理 三、多硬盘对数据安全的提升原理 四、多硬盘对容量的提升原理 五、磁盘阵列模式 六、飞牛NAS支持的存储模式 七、具体如何选择存储空间模式 在数字化时代,数据是个人和企业发展的核心资产,但面临硬盘损坏、病毒…

vue3: baidusubway using typescript

项目结构&#xff1a; <!--npm install -D tailwindcss-3d BaiduSubwayMap.vue npm install -D tailwindcss postcss autoprefixer--> <template><div class"relative w-full h-screen"><!-- 地图容器 --><div id"subway-container…

【递归、搜索与回溯】专题二、二叉树中的深搜

文章目录 1.计算布尔二叉树的值1.1 题目1.2 思路1.3 代码 2.求根节点到叶节点数字之和2.1 题目2.2 思路2.3 代码 3.二叉树剪枝3.1 题目3.2 思路3.3 代码 4.验证二叉搜索树4.1 题目4.2 思路4.3 代码 5.二叉搜索树中第K小的元素5.1 题目5.2 思路5.3 代码 6.二叉树的所有路径6.1 题…

Windows商店中的免费扫雷游戏应用

《扫雷》是一款经典的单人益智小游戏&#xff0c;1992年微软发布的Windows 3.1中加入该游戏&#xff0c;从此风靡全世界。游戏目标是通过逻辑推理&#xff0c;在最短的时间内根据点击格子出现的数字找出所有非雷格子&#xff0c;同时避免踩雷。 此Windows应用实现了经典扫雷的…

无法运用pytorch环境、改环境路径、隔离环境

一.未建虚拟环境时 1.创建新项目后&#xff0c;直接运行是这样的。 2.设置中Virtualenv找不到pytorch环境&#xff1f;因为此时没有创建新虚拟环境。 3.选择conda环境&#xff08;全局环境&#xff09;时&#xff0c;是可以下载环境的。 运行结果如下&#xff1a; 是全局环境…

古老的传说(Player、Stage)是否还能在蓝桥云课ROS中重现-250601(失败)

古老的传说是否还能在蓝桥云课ROS中重现-250601 经典复现何其难&#xff0c;百分之二就凉凉&#xff01; 古老的传说 那是很久很久以前的故事……上个世纪的一个机器人项目 Player、Stage这个项目最早起源于1999年&#xff0c;由美国南加州大学机器人研究实验室开发&#xff0…

机器学习:逻辑回归与混淆矩阵

本文目录&#xff1a; 一、逻辑回归Logistic Regression二、混淆矩阵&#xff08;一&#xff09;精确率precision&#xff08;二&#xff09;召回率recall&#xff08;三&#xff09;F1-score&#xff1a;了解评估方向的综合预测能力&#xff08;四&#xff09;Roc曲线&#xf…

Spring是如何实现属性占位符解析

Spring属性占位符解析 核心实现思路1️⃣ 定义占位符处理器类2️⃣ 处理 BeanDefinition 中的属性3️⃣ 替换具体的占位符4️⃣ 加载配置文件5️⃣ Getter / Setter 方法 源码见&#xff1a;mini-spring 在使用 Spring 框架开发过程中&#xff0c;为了实现配置的灵活性&#xf…

继承与多态

继承与多态的分析 继承继承与访问限定比较派生类和基类关系派生类的构造顺序基类对象&#xff08;指针&#xff09;派生类对象&#xff08;指针&#xff09;的转换重载和隐藏 虚函数静态绑定与动态绑定指针调用其他调用的绑定方式虚函数实现的依赖 多态 继承 继承的本质&#…

API异常信息如何实时发送到钉钉

#背景 对于一些重要的API&#xff0c;开发人员会非常关注API有没有报错&#xff0c;为了方便开发人员第一时间获取错误信息&#xff0c;我们可以使用插件来将API报错实时发送到钉钉群。 接下来我们就来实操如何实现 #准备工作 #创建钉钉群 如果已有钉钉群&#xff0c;可以跳…

Amazon GameLift实战指南:低成本构建高并发全球游戏服务器架构

一、为什么游戏服务器需要GameLift&#xff1f; 行业痛点 传统自建服务器&#xff1a;扩容慢、DDoS防御弱、全球延迟不均 开源解决方案&#xff08;如Agones&#xff09;&#xff1a;运维成本高、需K8s深度知识 云虚拟机手动扩缩容&#xff1a;响应延迟导致玩家流失 GameLi…