Rust: main.rs y lib.rs — cómo no confundirse con los módulos y acelerar el código

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Confusión de módulos en Rust: cómo main.rs y lib.rs vuelven loco (y cómo solucionarlo)

\n\n

¿Alguna vez has escrito en Rust, creado un nuevo proyecto, añadido main.rs y lib.rs — y de repente el compilador empezó a mostrar errores que parecían no tener sentido? ¿Te suena familiar? Si has buscado en Google "Rust modules confusion when there is main.rs and lib.rs", no estás solo. Esta pregunta en Stack Overflow ha acumulado miles de visitas, y con razón. La confusión con los módulos es uno de los problemas más comunes entre los principiantes (e incluso entre desarrolladores experimentados que vienen de otros lenguajes).

\n\n

En este artículo no solo analizaremos cómo funciona el sistema de módulos de Rust. Mostraremos cómo su organización correcta afecta directamente la optimización y el rendimiento de tu código. Aprenderás por qué lib.rs no es solo "otro archivo", sino una herramienta poderosa para acelerar la compilación y crear una API limpia. ¡Vamos allá!

\n\n

El problema: "¿Por qué el compilador no ve mis módulos?"

\n\n

Imagina: creaste un proyecto my_project con cargo new my_project. Por defecto, Cargo crea src/main.rs. Añades un segundo archivo — src/lib.rs — y escribes una función en él. Luego intentas llamarla desde main.rs — y obtienes un error:

\n\n
error[E0432]: unresolved import `my_project::some_function`\n --> src/main.rs:1:5\n  |\n1 | use my_project::some_function;\n  |     ^^^^^^^^^^^^^^^^^^^^^^^^^ no `some_function` in the root
\n\n

¿Un dolor familiar? ¿Cuál es el problema? Es simple: Rust considera main.rs y lib.rs como dos raíces de crate diferentes. Si no se especifica lo contrario en Cargo.toml, Cargo crea automáticamente dos crates: uno binario (desde main.rs) y uno de biblioteca (desde lib.rs). No se "ven" entre sí directamente hasta que especifiques explícitamente las dependencias.

\n\n

Esta es la famosa Rust modules confusion de la que todos hablan. Pero en lugar de enfadarte, convirtamos esta "característica" en una ventaja.

\n\n

Solución: cómo organizar los módulos correctamente

\n\n

Hay dos enfoques, y la elección depende de tu objetivo. Pero te adelantamos un spoiler: el segundo enfoque es mejor para el rendimiento.

\n\n

Opción 1: Todo en un solo crate (simple, pero no escalable)

\n\n

Si tu proyecto es pequeño, puedes declarar los módulos dentro de main.rs usando mod:

\n\n
// src/main.rs\nmod utils; // busca src/utils.rs o src/utils/mod.rs\n\nfn main() {\n    utils::do_something();\n}
\n\n

Esto funciona, pero si añades lib.rs, comenzará la confusión. lib.rs se convertirá en un crate separado, y los módulos de main.rs no estarán disponibles en él. Para scripts pequeños está bien, para proyectos serios no.

\n\n

Opción 2: Biblioteca + binario (el camino correcto para la optimización)

\n\n

La forma más adecuada es hacer de lib.rs el almacén principal de la lógica, y main.rs un envoltorio delgado para la ejecución. Así obtienes:

\n
    \n
  • Modularidad: toda la lógica de negocio en la biblioteca.
  • \n
  • Capacidad de prueba: la biblioteca se puede probar por separado.
  • \n
  • Rendimiento: el compilador optimiza mejor el código de la biblioteca si se usa repetidamente.
  • \n
\n\n

¿Cómo hacerlo? Simplemente:

\n
// src/lib.rs\npub mod utils;\n\npub fn run() {\n    utils::do_something();\n}\n\n// src/main.rs\nfn main() {\n    my_project::run(); // my_project — nombre del crate en Cargo.toml\n}
\n\n

Observa: main.rs ahora usa my_project::run(). Esto funciona porque Cargo ve lib.rs como una biblioteca con el nombre my_project. ¡Voilà — la confusión ha desaparecido!

\n\n

Optimización y rendimiento: por qué lib.rs es tu amigo

\n\n

Ahora lo más inte

Blogs

Book Recommendations