究竟什么被认为是对库箱的重大改变?

What exactly is considered a breaking change to a library crate?

Rust crates 使用 Semantic Versioning。因此,每个具有重大更改的版本都应该导致主要版本升级。 重大变更 通常被认为可能会破坏下游板条箱(代码取决于相关库)。

然而,在 Rust 中,很多东西都有可能破坏下游的板条箱。例如,更改(仅包括 添加到 )public 符号集可能是一个重大更改,因为下游板条箱可以使用 glob-imports (use foo::*;)将我们库的符号拉入它们的命名空间。因此,添加符号也可以破坏依赖的板条箱;参见 this example

同样,更改(添加或更改版本)我们的 依赖项集可能会破坏下游构建。您还可以想象下游板条箱依赖于我们 public 类型之一的特定大小。这很少(如果有的话)有用;我只是想表明:只要下游板条箱足够努力,一切都可能是一个突破性的变化。

有这方面的指导方针吗? 究竟什么被认为是重大变化,什么不是(因为它被认为是 "the user's fault")?

有一个关于这个主题的 Rust RFC:RFC 1105: API Evolution。它适用于任何 Rust 库项目,涵盖所有类型的更改(不仅仅是破坏性更改)以及它们如何影响语义版本控制。我将尝试总结 RFC 中的要点,以免使此答案成为仅 link 的答案。 :)

RFC 承认几乎任何对库的更改都可能导致客户端突然停止编译。因此,它定义了一组 major changes,这需要增加主版本号,以及一组 minor changes,这需要次要版本号的颠簸;并非所有重大更改都是重大更改

小改动的关键属性是必须有一种方法可以让客户通过稍微改变他们的源代码来提前避免破坏(例如,将 glob 导入更改为非 glob 导入,消除歧义调用与 UFCS 等),以使代码与更改之前的版本以及包含更改的版本(假设它是次要版本)兼容。微小的改变也不得迫使下游板条箱进行重大的破坏性改变以解决破损问题。


RFC 中定义的主要更改(截至 commit 721f2d74)是:

  • 将您的项目从与稳定编译器兼容切换到仅与夜间编译器兼容。
  • 重命名、移动或删除模块中的任何 public item
  • 当所有当前字段都是 public 时,将私有字段添加到结构中。
  • 向没有私有字段的结构添加 public 字段。
  • 正在向枚举添加新变体。
  • 正在向枚举变体添加新字段。
  • 将非默认项添加到特征。
  • 对特征项签名的任何重要更改。
  • 在现有类型上实现 fundamental 特征。
  • 收紧现有类型参数的界限。
  • 向函数添加或删除参数。
  • 未在 RFC 中列为次要更改的任何其他重大更改。

RFC 中定义的微小变化(自 commit 721f2d74 起,除非另有说明,否则会中断)是:

  • 更改箱子上 Cargo 功能的使用。
  • 正在模块中添加新的 public 项。
  • 在结构中至少已经存在一个私有字段时添加或删除私有字段(更改前后)[未中断].
  • 将具有所有私有字段(至少有一个字段)的元组结构转换为普通结构,反之亦然。
  • 将默认项添加到特征。
  • 向特征添加默认类型参数[未破坏].
  • 在现有类型上实现任何非基本特征。
  • 将任何项目添加到固有 impl
  • 更改函数的未记录行为。
  • 放宽现有类型参数的界限[不破坏]
  • 向类型或特征添加默认类型参数[未中断].
  • 通过将其类型替换为默认为先前类型的新类型参数来泛化现有结构或枚举字段[中断直到 issue 27336 被修复].
  • 正在为现有函数引入新类型参数。
  • 通过将类型替换为可以实例化为先前类型的新类型参数来泛化现有函数的参数或 return 类型。
  • 引入新的 l​​int warnings/errors。

有关解释和示例,请参阅 the RFC