В чём разница между `use` и `extern crate` в Rust?
Краткий ответ
extern crate — это устаревшая конструкция, которая в современных проектах (начиная с Rust 2018 edition) обычно не нужна. Вместо неё достаточно использовать use для импорта конкретных имён из внешних крейтов. Однако есть редкие исключения, когда extern crate всё ещё может пригодиться.
Подробное объяснение
Давайте разберёмся по порядку. В Rust есть две разные концепции:
- Внешний крейт — это библиотека, которую вы подключаете к своему проекту через
Cargo.toml(например,rand = "0.8"). - Импорт символов — это то, как вы используете модули, функции, типы и трейты из этого крейта в своём коде.
Раньше (до Rust 2018) нужно было явно сообщать компилятору: «Эй, я хочу использовать внешний крейт!». Для этого и служило extern crate rand;. Без этой строки компилятор не знал бы, что крейт rand существует, даже если он указан в Cargo.toml.
Начиная с Rust 2018 edition, компилятор автоматически видит все крейты, перечисленные в Cargo.toml. Поэтому extern crate стал необязательным. Теперь достаточно просто написать:
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
println!("{}", rng.gen_range(1..101));
}
Обратите внимание: use rand::Rng; импортирует трейт Rng, но сам крейт rand уже «виден» компилятору. Вы можете обращаться к его функциям через rand::thread_rng() или rand::random() напрямую, без use.
Когда extern crate всё ещё нужен?
Есть несколько ситуаций, где extern crate может быть полезен или даже необходим:
- Макросы. Некоторые макросы (например, из крейта
lazy_staticилиserde_derive) требуют явногоextern crateв старых версиях Rust. В современных проектах это обычно не нужно, но если вы используете Rust 2015 edition — придётся писать. - Переименование крейта. Если имя крейта конфликтует с локальным модулем, вы можете написать
extern crate rand as rng_crate;и потом обращаться к нему какrng_crate::Rng. - Явное указание атрибутов. Например,
extern crate serde_json as json;позволяет задать атрибуты вроде#[macro_use](хотя это тоже устарело). - no_std окружение. В встраиваемых системах или ядрах ОС, где нет стандартной библиотеки,
extern crateможет быть нужен для подключенияcoreилиalloc.
Практический совет
В 99% случаев вам нужен только use. Забудьте про extern crate, если только вы не поддерживаете старый код. Убедитесь, что в вашем Cargo.toml указана edition = "2021" (или хотя бы "2018"), и пишите код без лишних строк.
Пример правильного современного подхода:
// Cargo.toml:
// [dependencies]
// rand = "0.8"
// main.rs:
use rand::Rng;
fn main() {
let secret = rand::random::<u32>();
println!("Секретное число: {}", secret);
}
Этот код чистый, понятный и работает во всех современных версиях Rust.
<<Дополнение: что делать, если код не компилируется без extern crate?
Иногда новички сталкиваются с тем, что компилятор выдаёт ошибку вроде cannot find crate `some_crate`, даже если крейт указан в Cargo.toml. Чаще всего это происходит по одной из трёх причин:
- Устаревший проект. Проверьте файл
Cargo.toml: в секции[package]должно быть написаноedition = "2021"или"2018". Если там"2015", тоextern crateобязателен. - Макросы с атрибутом
#[macro_use]. В старых крейтах (например,logилиlazy_static) макросы импортировались через#[macro_use] extern crate log;. В современных версиях этих крейтов макросы можно импортировать обычнымuse log::info;. - Конфликт имён. Если у вас есть локальный модуль с тем же именем, что и внешний крейт, компилятор может запутаться. Решение: переименуйте крейт через
extern crate some_crate as sc;или переименуйте локальный модуль.
Если вы пишете новый проект — просто используйте edition = "2021" и забудьте про extern crate. Это сделает код короче и современнее.
Ответов пока нет.
Войдите чтобы оставить ответ