Algoritmos y Estructuras de Datos Herramientas Lenguaje de programación
!Prog C/C++ Rust
Linux Matemáticas
Mates Discretas
Programación Orientada a Objetos Sistemas Operativos

Módulos


[words: 786] [reading time: 4min] [size: 29915 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:

1cargo 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:

 1mod example {
 2  mod other_module {
 3    fn other_example() {
 4      todo!();
 5    }
 6  }
 7  fn foo_example() {
 8    todo!();
 9  }
10}

Module tree:

1crate
2└─ example
3   ├─ other_module
4   │  └─ other_example
5   └─ 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:

1pub mod example {
2  pub fn foo() {
3    todo!();
4  }
5}

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

1a::very::long::and::verbose::direction::foo();
2
3use a::very::long::and::verbose::direction;
4direction::foo();
5
6use a::very::long::and::verbose::direction::foo;
7foo();

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

1a::very_long_and_verbose_direction::foo();
2
3use a::very_long_and_verbose_direction as dir;
4dir::foo();

Re-exportando nombres con pub use

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

1use base::path;
2use base::path::one::path;
3use base::path::other_path;
4
5use base::path::{self, one::path, other_path};

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

1use 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:

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

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:

1src
2├─ main.rs
3└─ other.rs

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

1mod other;
2
3fn main() {
4  other::foo();
5}

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).

1mod other;
2use other::module;
3
4fn main() {
5  module::foo();
6}

¿Qué sucede al tener subdirectorios?

1src
2├─ module
3│  ├─ mod.rs
4│  └─ other.rs
5└─ 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:

1mod module;
2
3fn main() {
4  module::other::foo();
5}

En src/module/mod.rs:

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