是否记录了 Cargo 可以下载和捆绑同一个箱子的多个版本?

Is it documented that Cargo can download and bundle multiple versions of the same crate?

通过分叉和尝试一些代码,我注意到 Cargo 可以下载并捆绑同一项目中同一 crate 的多个版本(例如 native-tls 0.1.5 和 0.2.1)。看错版本的文档浪费了我很多时间

我已经查找了有关此行为的一些信息,但没有找到任何信息。这在某处记录了吗?

是否有一种简单的方法来 determine/detect 您正在处理的代码(当前编辑的文件)使用的版本?或者,如果需要同一个 crate 的两个版本,我们可以告诉 Cargo 显示一些 warnings/prevent 构建吗?

Cargo 确实可以 link 一些 crate 的多个版本,但这些版本中只有一个可以是直接依赖。其他的都是间接引用。

直接引用始终是 Cargo.toml 引用的版本并在 Cargo.lock 的顶层(而间接引用在 dependencies 小节中)。

不幸的是,我不确定记录了多少。

在设计 Rust 以允许同一个 crate 的多个版本时,这是一个有意识的决定。

您之前可能听说过Dependency Hell,当 2 个(或更多)依赖项 A 和 B 具有共同的依赖项 C,但每个都需要一个与另一个不兼容的版本时,就会发生这种情况。

Rust 旨在确保这不会成为问题。

一般来说,cargo 会尝试找到一个通用的版本来满足所有的要求。只要 crate 作者正确使用 SemVer,并且需求给予足够的回旋余地,单版本的依赖是可以被成功计算和使用的。

但是,有时需要同一依赖项的多个版本,例如您的情况,因为 0.1.x 和 0.2.x 被认为是两个不同的主要版本。在这种情况下,Rust 有两个特性允许在同一个二进制文件中使用两个版本:

  • 每个版本的唯一哈希值附加到每个符号。
  • 类型系统将来自两个 C 版本的相同类型 Foo 视为不同类型。

当然有一个限制。如果 A 的函数 returns 是 C::Foo 的实例,而你试图将它传递给 B 的函数,编译器将拒绝它(它认为这两种类型是不同的)。这是一个棘手的问题1.

任何时候对 C 的依赖是内部的,或者 C 的使用是孤立的,否则它会自动运行。正如您的体验所示,它是如此无缝,用户甚至可能没有意识到它正在发生。

1 查看 crate 作者可以使用的 dtolnay trick 以允许某些类型可以互换。