Rust 中的 extern crate 和 use:陷阱在哪里以及如何避免踩坑
\n\n如果你曾经写过哪怕几行 Rust 代码,你很可能遇到过 extern crate 和 use 这两种结构。乍一看,它们似乎在做同一件事——引入外部代码。但魔鬼,一如既往,藏在细节中。这个问题 位列 Stack Overflow 最热门问题之列(数千次浏览!),新手们经常在这里混淆。让我们一劳永逸地弄清楚 extern crate 和 use 的区别,它们各自的魔法发生在哪里,以及如何避免典型错误。
简要说明:它们分别是什么
\n\n想象一下,你的 Rust 项目是一栋大房子。extern crate 就像把建筑材料运到工地上。你告诉编译器:“嘿,这个装砖头的箱子(crate)我想用,把它运过来。” 没有这个命令,编译器甚至不会知道外部库的存在。
use 则像是房子内部的导航。你说:“我希望这个房间(模块)的门直接通向厨房(特定的类型或函数)。” use 为已知的模块和类型创建别名(短路径),这样你就不必每次都写完整的路径。
简单来说:extern crate 回答“我们到底能使用什么?”这个问题,而 use 回答“我们如何更方便地引用它?”这个问题。
历史背景:为什么大家都会混淆
\n\n混淆并非凭空产生。在旧版本的 Rust 中(2018 edition 之前),extern crate 对于任何外部 crate 都是必需的。看起来像这样:
// Rust 2015 — 旧风格\nextern crate serde;\nuse serde::{Serialize, Deserialize};\n\n从 Rust 2018 edition 开始,编译器学会了自动从 Cargo.toml 中查找依赖项。现在,对于大多数 crate,不再需要写 extern crate。只需在 Cargo.toml 中添加依赖项,然后直接使用 use 即可:
// Rust 2018+ — 新风格(extern crate 非必需)\nuse serde::{Serialize, Deserialize};\n\n这就是新手噩梦的开始。他们看到旧示例中使用 extern crate,新示例中却没有,于是试图弄清楚它到底什么时候需要。剧透:需要,但只在极少数情况下。
何时 extern crate 仍然需要(这很重要!)
\n\n有三种情况离不开 extern crate:
- \n
- 通过
#[link]链接系统库——如果你正在编写 C/C++ 代码的绑定并使用#[link(name = "sqlite3")]属性,那么extern crate是必需的。 \n - 全局宏——某些 crate(例如
log)会导出宏,这些宏需要在整个程序中可见。在 Rust 2018 中,你需要写extern crate log;来实现这一点。 \n - 使用非标准 crate 名称进行编译——如果你使用
extern crate my_crate as foo;来重命名 crate。 \n
在所有其他情况下,extern crate 都是过去的遗留产物。但许多开发者习惯性地继续写它,而新手则从旧教程中复制代码。
使用 extern crate 和 use 时的前 5 个错误
\n\n错误 #1:在不必要的地方使用 extern crate
\n\n最常见的问题。你在 Cargo.toml 中添加了一个 crate,然后写了 extern crate rand;——代码能运行。但这是多余的一行。在现代项目(Rust 2018+)中,它只会污染代码,并可能让其他开发者感到困惑。
// 不好(在 Rust 2018+ 中多余)