¿Cómo incluir un módulo de otro archivo del mismo proyecto?

130

Siguiendo esta guía creé un proyecto Cargo.

src/main.rs

fn main() {
    hello::print_hello();
}

mod hello {
    pub fn print_hello() {
        println!("Hello, world!");
    }
}

que corro usando

cargo build && cargo run

y se compila sin errores. Ahora estoy tratando de dividir el módulo principal en dos, pero no puedo averiguar cómo incluir un módulo de otro archivo.

Mi árbol de proyectos se ve así

├── src
    ├── hello.rs
    └── main.rs

y el contenido de los archivos:

src/main.rs

use hello;

fn main() {
    hello::print_hello();
}

src/hello.rs

mod hello {
    pub fn print_hello() {
        println!("Hello, world!");
    }
}

Cuando lo compilo cargo buildconsigo

error[E0432]: unresolved import `hello`
 --> src/main.rs:1:5
  |
1 | use hello;
  |     ^^^^^ no `hello` external crate

Intenté seguir las sugerencias del compilador y modifiqué main.rsa:

#![feature(globs)]

extern crate hello;

use hello::*;

fn main() {
    hello::print_hello();
}

Pero esto todavía no ayuda mucho, ahora entiendo esto:

error[E0463]: can't find crate for `hello`
 --> src/main.rs:3:1
  |
3 | extern crate hello;
  | ^^^^^^^^^^^^^^^^^^^ can't find crate

¿Existe un ejemplo trivial de cómo incluir un módulo del proyecto actual en el archivo principal del proyecto?

Cra
fuente
1
posible duplicado de las importaciones básicas
Levans

Respuestas:

239

No necesita el mod helloen su hello.rsarchivo. El código de cualquier archivo excepto la raíz de la caja ( main.rspara ejecutables, lib.rspara bibliotecas) se coloca automáticamente en un espacio de nombres en un módulo.

Para incluir el código de hello.rsen su main.rs, use mod hello;. Se expande al código que está en hello.rs(exactamente como lo tenía antes). La estructura de su archivo sigue igual y su código debe cambiarse ligeramente:

main.rs:

mod hello;

fn main() {
    hello::print_hello();
}

hello.rs:

pub fn print_hello() {
    println!("Hello, world!");
}
Renato Zannon
fuente
1
Pregunta tardía, ¿no funcionaría también si la especifico con use hello en lugar de mod hello?
Christian Schmitt
16
@ChristianSchmitt No, son cosas diferentes. usees solo una cosa de espacio de nombres, mientras que modextrae el archivo. Utilizaría use, por ejemplo, poder llamar a la print_hellofunción sin tener que prefijar el espacio de nombres
Renato Zannon
25

Si desea tener módulos anidados ...

Óxido 2018

Ya no es necesario tener el archivo mod.rs(aunque todavía es compatible). La alternativa idiomática es nombrar el archivo con el nombre del módulo:

$ tree src
src
├── main.rs
├── my
│   ├── inaccessible.rs
│   └── nested.rs
└── my.rs

main.rs

mod my;

fn main() {
    my::function();
}

my.rs

pub mod nested; // if you need to include other modules

pub fn function() {
    println!("called `my::function()`");
}

Óxido 2015

Necesita poner un mod.rsarchivo dentro de su carpeta con el mismo nombre que su módulo. Rust by Example lo explica mejor.

$ tree src
src
├── main.rs
└── my
    ├── inaccessible.rs
    ├── mod.rs
    └── nested.rs

main.rs

mod my;

fn main() {
    my::function();
}

mod.rs

pub mod nested; // if you need to include other modules

pub fn function() {
    println!("called `my::function()`");
}
amxa
fuente
4
Supongamos que yo quería usar algo de inaccessible.rsen nested.rs... ¿cómo iba a hacer eso?
Heman Gandhi
Para acceder a un archivo .rs hermano desde un archivo que no sea main.rs, use el atributo de ruta. Entonces, en la parte superior de nested.rs, agregue lo siguiente: #[path = "inaccessible.rs"]y en la siguiente línea:mod inaccessible;
Gardener
@Gandhi Ver el atributo de ruta
Jardinero
2
@HemanGandhi agrega mod inaccessible;para my/mod.rsconvertirlo en un submódulo de my, luego accede al módulo hermano desde la nested.rsruta relativa super::inaccessible::function(). no necesitas pathatributo aquí.
Artin
9

Realmente me gusta la respuesta de Gardener. He estado usando la sugerencia para las declaraciones de mi módulo. Alguien por favor intervenga si hay un problema técnico con esto.

./src
├── main.rs
├── other_utils
│   └── other_thing.rs
└── utils
    └── thing.rs

main.rs

#[path = "utils/thing.rs"] mod thing;
#[path = "other_utils/other_thing.rs"] mod other_thing;

fn main() {
  thing::foo();
  other_thing::bar();
}

utils / thing.rs

pub fn foo() {
  println!("foo");
}

other_utils / other_thing.rs

#[path = "../utils/thing.rs"] mod thing;

pub fn bar() {
  println!("bar");
  thing::foo();
}
rodo
fuente
Tuve que usar este 'truco' para reexportar fncon el mismo nombre que el archivo en el que estaba.#[path = "./add_offer.rs"] mod _add_offer; pub use self::_add_offer::add_offer;
Arek Bal
esta debería ser la respuesta aceptada en mi opinión
Homam Bahrani