Algoritmos y Estructuras de Datos Compiladores e Intérpretes Herramientas Lenguaje de programación
!Prog C/C++
Linux Matemáticas
Mates Discretas
Programación Orientada a Objetos Redes y Computación Distribuida Sistemas Operativos

Módulos


[words: 761] [reading time: 4min] [size: 14190 bytes]

Rust module system

Crates y Paquetes

Un crate (caja) es solo una librería o un ejecutable. El crate root es el archivo de código fuente base, el que se compila por defecto, o el principal, digamos.

Un paquete es el conjunto de crates que tienen cierta funcionalidad. Existen algunas normas sobre estos:

  1. Debe tener al menos un crate (paquete vacío?).
  2. Puede tener entre 0 y 1 (inclusive) crates de librería.
  3. Puede tener los crates binarios que sean necesarios.

Entonces:

cargo run --bin <nombre>

Al usar cargo new <nombre>, estamos creando un paquete llamado <nombre> (lo que contenga un archivo Cargo.toml y un directorio src será un paquete). Si, de base, contiene src/main.rs será binario, o src/lib.rs será librería.

Módulos y direcciones

Un módulo nos permite organizar mejor nuestro código dentro del propio crate. Se definen con la palabra clave mod:

mod example {
  mod other_module {
    fn other_example() {
      todo!();
    }
  }
  fn foo_example() {
    todo!();
  }
}

Module tree:

crate
└─ example
   ├─ other_module
   │  └─ other_example
   └─ foo_example

Para acceder a las diferentes partes usamos las direcciones. Estas están compuestas de los nombres del camino que se debe tomar. Hay varias formas:

Además de usar esta dirección, los módulos y las funciones deben de ser públicas, dado que pueden ser únicamente para el funcionamiento interno del módulo. Para cambiar su privacidad se usa pub:

pub mod example {
  pub fn foo() {
    todo!();
  }
}

Tener que escribir estas largas direcciones para utilizar determinada dirección puede ser engorroso, por eso tenemos la palabra clave use:

a::very::long::and::verbose::direction::foo();

use a::very::long::and::verbose::direction;
direction::foo();

use a::very::long::and::verbose::direction::foo;
foo();

En el caso de que el último nombre sea muy grande, o prefiramos cambiarlo en caso de que se repitan nombres, podemos usar as:

a::very_long_and_verbose_direction::foo();

use a::very_long_and_verbose_direction as dir;
dir::foo();

Re-exportando nombres con pub use

Podemos también agrupar numerosos uses que tengan el mismo prefijo:

use base::path;
use base::path::one::path;
use base::path::other_path;

use base::path::{self, one::path, other_path};

O incluso, si queremos usar todo su contenido público (glob operator):

use base::path::*;

Usando paquetes externos

Después de añadir un paquete a nuestro archivo Cargo.toml, y para poder usar sus funciones, usamos use:

[dependencies]
pkg_name = "*"
use pkg_name::some::path;
fn main() {
  path::foo();
}

Varios archivos de código fuente

Al parecer tenemos las siguientes reglas en cuanto al sistema de módulos de Rust y sus direcciones:

  1. Un archivo de código fuente es un módulo por sí mismo, excepto los especiales: main.rs, lib.rs y mod.rs.
  2. Un directorio es solo un componente de la ruta del módulo.
  3. El archivo mod.rs es el módulo de la carpeta.

De la forma que al describir los paths a nuestras funciones y demás, estas coincidirán en con la estructura de archivos.


Veamos por ejemplo el siguiente caso:

src
├─ main.rs
└─ other.rs

Para llamar la función foo en other.rs, dentro de main.rs escribiríamos:

mod other;

fn main() {
  other::foo();
}

La palabra clave use funciona simplemente para evitar tener que escribir toda la dirección. En este ejemplo, dentro del archivo other, hay un módulo llamado module.

Hay que tener en cuenta que deberás seguir utilizando la última dirección para evitar que se confundan módulos.

Estas direcciones pueden ser tanto relativas al directorio actual, como absolutas (usando crate al principio de todo si se refiere al crate base).

mod other;
use other::module;

fn main() {
  module::foo();
}

¿Qué sucede al tener subdirectorios?

src
├─ module
│  ├─ mod.rs
│  └─ other.rs
└─ main.rs

En este caso, es necesario disponer de un archivo mod.rs que se cargará al usar module, ya que como veíamos antes, las carpetas son también módulos y mod.rs es donde se guarda su código.

En src/main.rs:

mod module;

fn main() {
  module::other::foo();
}

En src/module/mod.rs:

pub mod other;
Anterior: Macros Volver a Rust Siguiente: Strings