extern crate y use en Rust: cuál es el truco y cómo no pisar el rastrillo
\n\nSi alguna vez has escrito al menos un par de líneas en Rust, seguro que te has topado con las construcciones extern crate y use. A primera vista parece que hacen lo mismo: importar código externo. Pero el diablo, como siempre, está en los detalles. Esta pregunta está entre las más populares en Stack Overflow (¡miles de visitas!), y los principiantes se confunden constantemente. Aclaremos de una vez por todas en qué se diferencia extern crate de use, dónde ocurre cada magia y cómo evitar errores típicos.
Brevemente sobre lo principal: qué es qué
\n\nImagina que tu proyecto en Rust es una casa grande. extern crate es la entrega de materiales de construcción al terreno. Le dices al compilador: «Oye, esta caja de ladrillos (crate) quiero usarla, tráela». Sin este comando, el compilador ni siquiera sabrá de la existencia de la biblioteca externa.
use es la navegación interna dentro de la casa. Dices: «Quiero que la puerta de esta habitación (módulo) lleve directamente a la cocina (tipo o función específica)». use crea alias (rutas cortas) para módulos y tipos ya conocidos, para no tener que escribir la ruta completa cada vez.
En pocas palabras: extern crate responde a la pregunta «¿qué podemos usar en absoluto?», mientras que use responde a «¿cómo nos es más cómodo referirnos a ello?».
Contexto histórico: por qué todos se confunden
\n\nLa confusión no surgió de la nada. En versiones antiguas de Rust (antes de la edición 2018), extern crate era obligatorio para cualquier crate externo. Se veía así:
// Rust 2015 — estilo antiguo\nextern crate serde;\nuse serde::{Serialize, Deserialize};\n\nA partir de Rust 2018 edition, el compilador aprendió a encontrar las dependencias por sí mismo desde Cargo.toml. Ahora, escribir extern crate para la mayoría de los crates no es necesario. Basta con añadir la dependencia en Cargo.toml y usar directamente use:
// Rust 2018+ — nuevo estilo (extern crate no es obligatorio)\nuse serde::{Serialize, Deserialize};\n\nAquí es donde empieza el infierno para los principiantes. Ven ejemplos antiguos donde se usa extern crate, ejemplos nuevos donde no aparece, e intentan entender cuándo sigue siendo necesario. Spoiler: es necesario, pero en casos muy raros.
Cuándo extern crate sigue siendo necesario (¡y es importante!)
\n\nHay tres situaciones en las que no se puede prescindir de extern crate:
- \n
- Enlace con bibliotecas del sistema mediante
#[link]— si escribes bindings para código C/C++ y usas el atributo#[link(name = "sqlite3")], entoncesextern cratees obligatorio. \n - Macros globales — algunos crates (por ejemplo,
log) exportan macros que deben ser visibles en todo el programa. En Rust 2018, para esto hay que escribirextern crate log;. \n - Compilación con nombres de crate no estándar — si usas
extern crate my_crate as foo;para renombrar un crate. \n
En todos los demás casos, extern crate es un artefacto del pasado. Pero muchos desarrolladores por costumbre siguen escribiéndolo, y los principiantes copian código de tutoriales antiguos.
Top 5 errores al trabajar con extern crate y use
\n\nError nº1: Usar extern crate donde no es necesario
\n\nEl problema más frecuente. Añades un crate en Cargo.toml, luego escribes extern crate rand; — y el código funciona. Pero es una línea innecesaria. En proyectos modernos (Rust 2018+) solo ensucia el código y puede confundir a otros desarrolladores.
// Mal (redundante en Rust 2018+)\nextern crate rand;\n\n// Bien (solo use es suficiente)\nuse rand::Rng;