rust - 为什么 cargo build 不显示具有不兼容依赖项的编译错误?
问题描述
由于这个问题涉及多个依赖关系,我不确定从哪个方向寻找重现它,我希望可以根据具体示例询问它。这个问题背后的更一般的模式是:存在依赖链user => libExtension => libBase
并且libExtension
不libBase
兼容。
在geo-booleanop项目中,我们遇到了一个我们无法完全理解的有趣问题。它涉及以下软件包的相互作用:
- geo-types (
libBase
):一个核心库,提供基本类型,如线条、矩形、多边形等。 - geo-booleanop (
libExtension
):建立在地理类型之上的库,用一个新功能对其进行了扩展:BooleanOp
具有交叉/联合/...等功能的新特征,并针对地理类型中的多边形类型实现。 - 任何将地理类型和地理布尔运算结合在一起的用户包,目的是使用
BooleanOp
多边形的特征。
包 geo-types 最近从 0.4 版到 0.5 版发生了重大变化,例如,它将其Rect
类型的一些字段从 pub 字段更改为 getter。
geo-booleanop 包尚未用于此更改,即,它仍然显式使用这些 pub 字段。当前,Cargo.toml
geo-booleanop 指定geo-types = "0.4"
,并且尝试将其提升到 0.5 并cargo build
在 geo-booleanop 内执行会导致在 pub 字段访问时出现编译器错误,如预期的那样。
现在令人惊讶的是:当创建一个结合了最新版本的 geo-types 和 geo-booleanop 的用户包时,我们cargo build
在用户包中看到以下输出:
$ cargo build
[...]
Compiling geo-booleanop v0.2.1
Compiling geo-types v0.5.0
[...]
error[E0599]: no method named `union` found for type `geo_types::polygon::Polygon<{float}>` in the current scope
--> src/main.rs:21:23
|
21 | let union = poly1.union(&poly2);
| ^^^^^ method not found in `geo_types::polygon::Polygon<{float}>`
这令人惊讶,因为:
- 根本不可能将 geo-booleanop v0.2.1 与地理类型 v0.5.0 结合起来编译,因为它们不兼容。
- 关于没有命名方法的错误
union
令人困惑,因为用户代码做了所有正确的事情来将BooleanOp
特征带入范围,这应该为多边形提供准确的方法。 BooleanOp
具有讽刺意味的是,编译器还输出未使用特征导入的警告。
我的问题是:
- 为什么
cargo build
不显示突出显示依赖项不兼容的编译错误? - 如果这是设计使然,我们可以在 geo-booleanop 网站上做些什么来让我们的用户更容易掌握这些问题吗?目前,他们在编写代码方面做的一切都是正确的,以将 trait 带入范围,但编译器的行为就像缺少 trait 一样——而实际上它是版本不匹配。我们可以在图书馆网站上强制执行更明确的错误吗?
详细信息以防万一:
- 该
BooleanOp
特征在其底层浮点类型中是通用的(参见实现)。这是否会导致问题,因为在客户端代码像在其他编程语言中一样使用泛型之前,不会实例化泛型? - 这是复制的客户端代码:main.rs和Cargo.toml。
解决方案
我将您的情况总结如下:
- 您的 Cargo.toml 取决于
geo-booleanop
0.2.1 和geo-types
0.5.0 geo-booleanop
0.2.1 取决于geo-types
0.4.x
如果您查看 Cargo.lock 文件,您会注意到有两个[[package]]
条目 for geo-types
,一个 for0.4.x
和一个 for 0.5.0
。
当同一个项目的两个(传递)依赖需求不兼容时,cargo 实际上会尝试编译它们。Cargo 不会将间接依赖项暴露给您的 crate,因此 Cargo 会分别构建两个版本,就好像它们没有相同的 crate 名称一样。只要你不尝试使用geo-types
with geo-booleanop
,它们实际上可以独立工作。
为了清楚起见,我将这两个版本分别称为geo_types_04
和geo_types_05
。geo-booleanop 适用于名为 的依赖项geo_types_04
,geo_types_04
它不会暴露给您的 crate,因此您根本不需要关心是否geo_types_04
使用。
只有当geo-booleanop
公开一个接受/返回在geo_types_04
. 然后你假设它是geo_types_05
,导致不兼容。
这次您的错误实际上是更具可读性的错误之一。有时您会遇到错误,例如Expected geo_types::Line, got geo_types::Line
因为接受的函数geo_types_04::Line
是用geo_types_05::Line
.