En esta página
Módulos, crates y el sistema de paquetes
El sistema de módulos de Rust
Rust organiza el código con un sistema de módulos explícito y jerárquico. Los módulos controlan la privacidad de los items (funciones, structs, enums, traits) y organizan el espacio de nombres.
La jerarquía: paquetes, crates y módulos
Paquete (package)
├── Cargo.toml
└── Crates
├── Crate binario (src/main.rs) — produce un ejecutable
└── Crate biblioteca (src/lib.rs) — produce una librería reutilizable
└── Módulos
├── módulo::submódulo::item
└── ...Un paquete puede tener uno o más crates. Un crate tiene un "crate root" (main.rs o lib.rs). Los módulos organizan el código dentro de un crate.
Módulos inline
// src/main.rs
mod frutas {
// pub: visible fuera del módulo
pub struct Fruta {
pub nombre: String,
calorias: u32, // privado
}
impl Fruta {
pub fn nueva(nombre: &str, calorias: u32) -> Self {
Fruta {
nombre: nombre.to_string(),
calorias,
}
}
pub fn calorias(&self) -> u32 {
self.calorias
}
}
pub mod tropicales {
use super::Fruta; // super: módulo padre
pub fn mango() -> Fruta {
Fruta::nueva("mango", 60)
}
pub fn papaya() -> Fruta {
Fruta::nueva("papaya", 43)
}
}
}
fn main() {
// Ruta absoluta desde el crate root
let f = frutas::Fruta::nueva("manzana", 52);
println!("{}: {} cal", f.nombre, f.calorias());
// Acceso a submódulo
let m = frutas::tropicales::mango();
println!("{}: {} cal", m.nombre, m.calorias());
}Módulos en archivos separados
Para proyectos grandes, cada módulo vive en su propio archivo:
src/
├── main.rs
├── matematicas.rs ← mod matematicas;
└── matematicas/
├── mod.rs (alternativa: o usar matematicas.rs)
└── avanzado.rs ← pub mod avanzado;// src/main.rs
mod matematicas; // Busca src/matematicas.rs o src/matematicas/mod.rs
use matematicas::sumar;
use matematicas::avanzado::factorial;
fn main() {
println!("3 + 4 = {}", sumar(3.0, 4.0));
println!("5! = {}", factorial(5));
}// src/matematicas.rs
pub mod avanzado; // Busca src/matematicas/avanzado.rs
pub fn sumar(a: f64, b: f64) -> f64 { a + b }
pub fn restar(a: f64, b: f64) -> f64 { a - b }
pub fn multiplicar(a: f64, b: f64) -> f64 { a * b }// src/matematicas/avanzado.rs
pub fn factorial(n: u64) -> u64 {
(1..=n).product()
}
pub fn combinatorio(n: u64, r: u64) -> u64 {
if r > n { return 0; }
factorial(n) / (factorial(r) * factorial(n - r))
}La keyword `use`: importar paths
mod geometria {
pub mod formas {
pub struct Circulo(pub f64);
pub struct Cuadrado(pub f64);
}
}
// Importar un item específico
use geometria::formas::Circulo;
// Importar múltiples items con llaves
use geometria::formas::{Circulo as C, Cuadrado};
// Importar todo (glob import) — úsalo con cuidado
use geometria::formas::*;
fn main() {
let c = Circulo(5.0);
let s = Cuadrado(4.0);
println!("Radio: {}, Lado: {}", c.0, s.0);
}Re-exportar con `pub use`
// src/lib.rs
mod implementacion {
pub struct Conexion {
pub url: String,
}
impl Conexion {
pub fn nueva(url: &str) -> Self {
Conexion { url: url.to_string() }
}
}
}
// Re-exportar: los usuarios pueden usar mi_crate::Conexion
// en lugar de mi_crate::implementacion::Conexion
pub use implementacion::Conexion;Cargo.toml: dependencias
El archivo Cargo.toml es el manifiesto del proyecto:
[package]
name = "mi-app"
version = "0.1.0"
edition = "2021"
authors = ["David Morales <[email protected]>"]
description = "Mi aplicación Rust"
[dependencies]
# Versión semántica
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
# Caret: ^1.0 = >=1.0.0, <2.0.0
tokio = { version = "^1.0", features = ["full"] }
# Tilde: ~1.2 = >=1.2.0, <1.3.0
log = "~0.4"
# Versión exacta
chrono = "=0.4.38"
# Desde git
# mi-crate = { git = "https://github.com/usuario/mi-crate" }
# Desde ruta local (para workspaces)
# mi-util = { path = "../mi-util" }
[dev-dependencies]
# Solo para tests
pretty_assertions = "1"
[build-dependencies]
# Para scripts de build (build.rs)
cc = "1"
[profile.release]
opt-level = 3
lto = trueWorkspaces: múltiples crates en un repositorio
Para proyectos grandes con múltiples crates relacionados:
# Cargo.toml raíz (workspace)
[workspace]
members = [
"core",
"api-server",
"cli",
"utils",
]
resolver = "2"
[workspace.dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }# core/Cargo.toml
[package]
name = "mi-core"
version = "0.1.0"
edition = "2021"
[dependencies]
serde.workspace = true # Usa la versión del workspaceCrates esenciales del ecosistema
| Crate | Propósito |
|---|---|
serde + serde_json |
Serialización/deserialización |
tokio |
Runtime async |
reqwest |
HTTP client |
clap |
CLI parsing |
thiserror |
Tipos de error con derive |
anyhow |
Manejo de errores en aplicaciones |
log + env_logger |
Logging |
chrono |
Fechas y horas |
regex |
Expresiones regulares |
rand |
Números aleatorios |
Agregar y usar una dependencia real
cargo add serde --features derive
cargo add serde_jsonuse serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Producto {
id: u32,
nombre: String,
precio: f64,
disponible: bool,
}
fn main() {
let producto = Producto {
id: 1,
nombre: String::from("Teclado Mecánico"),
precio: 89.99,
disponible: true,
};
// Serializar a JSON
let json = serde_json::to_string_pretty(&producto).unwrap();
println!("{json}");
// Deserializar desde JSON
let json_entrada = r#"{"id":2,"nombre":"Mouse","precio":29.99,"disponible":false}"#;
let producto2: Producto = serde_json::from_str(json_entrada).unwrap();
println!("{:?}", producto2);
}Con el sistema de módulos dominado, pasamos a una de las características más elegantes de Rust: closures e iteradores — la forma funcional de transformar datos.
pub(crate) vs pub vs pub(super)
Rust tiene visibilidad granular: pub hace el item público para todos, pub(crate) lo limita al crate actual, pub(super) lo limita al módulo padre, y sin pub es privado al módulo actual. Prefiere pub(crate) sobre pub cuando el item no forma parte de la API pública de la librería.
crates.io y Cargo.lock
Cargo.lock garantiza builds reproducibles — guarda las versiones exactas de todas las dependencias. Para proyectos binarios debes commitear Cargo.lock al repositorio. Para librerías, generalmente NO se commitea (los consumidores de la librería resolverán las versiones).
// src/lib.rs — raíz del crate biblioteca
// Módulos inline
pub mod matematicas {
pub fn sumar(a: f64, b: f64) -> f64 { a + b }
pub fn restar(a: f64, b: f64) -> f64 { a - b }
// Submódulo
pub mod avanzado {
pub fn factorial(n: u64) -> u64 {
(1..=n).product()
}
pub fn fibonacci(n: u32) -> u64 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
}
}
// Módulo privado (sin pub)
mod interno {
pub(super) fn ayudante() -> &'static str { "ayuda interna" }
}
pub fn usar_interno() -> &'static str {
interno::ayudante()
}
// Re-exportar con use pub
pub use matematicas::avanzado::factorial;
Inicia sesión para guardar tu progreso