如何使用 Cargo/Rust 在模块中包含同一目录中的文件?

How to include files from same directory in a module using Cargo/Rust?

我有一个 Cargo 项目,由同一目录中的三个文件组成:main.rsmod1.rsmod2.rs

我想将函数从 mod2.rs 导入到 mod1.rs,就像将函数从 mod1.rs 导入到 main.rs 一样。
我已经阅读了所需的文件结构,但我不明白 - 将所有导入的文件命名为 mod 会导致编辑器出现轻微混乱,而且这只会使项目层次结构复杂化。

有没有办法像在 Python 或 C++ 中那样独立于目录结构 import/include 文件?

main.rs:

mod mod1; // Works

fn main() {
    println!("Hello, world!");
    mod1::mod1fn();
}

mod1.rs:

mod mod2; // Fails

pub fn mod1fn() {
    println!("1");
    mod2::mod2fn();
}

mod2.rs:

pub fn mod2fn() {
    println!("2");
}

构建结果:

error: cannot declare a new module at this location
 --> src\mod1.rs:1:5
  |
1 | mod mod2;
  |     ^^^^
  |
note: maybe move this module `src` to its own directory via `src/mod.rs`
 --> src\mod1.rs:1:5
  |
1 | mod mod2;
  |     ^^^^
note: ... or maybe `use` the module `mod2` instead of possibly redeclaring it
 --> src\mod1.rs:1:5
  |
1 | mod mod2;
  |     ^^^^

我不能 use 因为它在任何地方都不作为模块存在,而且我不想修改目录结构。

所有顶级模块声明都应该放在 main.rs 中,如下所示:

mod mod1;
mod mod2;

fn main() {
    println!("Hello, world!");
    mod1::mod1fn();
}

然后您可以 use crate::mod2mod1:

use crate::mod2;

pub fn mod1fn() {
    println!("1");
    mod2::mod2fn();
}

如果您还没有阅读 the chapter on modules in the new version of the Rust book,我建议您阅读 - 对于刚接触该语言的人来说,它们可能有点令人困惑。

如果你不希望你的 mod 语句全部在你的主文件中(例如:在 main.rs 中你不会在某些模块中使用一些 public 成员,在这个例如 mod2) 您可以执行以下操作:

以这种方式构建您的 src

main.rs
my_module:
  mod.rs
  mod1.rs
  mod2.rs

那么你可以 mod my_moduleuse my_module::mod1,像这样:

main.rs:

mod my_module;
use my_module::mod1;

fn main() {
    println!("Hello, world!");
    mod1::mod1fn();
}

my_module/mod.rs

pub mod mod1;
pub mod mod2;

my_module/mod1.rs

use super::mod2;

pub fn mod1fn() {
    println!("1");
    mod2::mod2fn();
}

每个文件都是一个模块,如果不创建新的嵌套模块就无法导入另一个文件。

一个。在模块索引文件中定义模块

按照@giuliano-oliveira's answer的建议。

src/lib.rs/src/main.rs/src/foo/mod.rs中添加pub mod mod1; pub mod mod2;

b。使用 #[path]

main.rs

#[path = "./mod2.rs"]
mod mod2;

fn run() { mod2::mod2fn() }

为什么?

这是新 Rust 开发者的一个常见陷阱,这是可以理解的。

造成混淆的原因是 mod X 同一文件夹中文件的行为不一致。您可以在 lib.rs 中使用 mod X,其中 显示为 导入与其相邻的文件,但您不能在 mod1.rsmod2.rs.

每个文件的代码属于一个模块。 文件模块的完整路径(例如foo::bar::baz)而不是文件的位置,决定了它如何解析mod X。你可以把它想象成每个模块都有一个固定的精神家园,但它可能有成员在层次结构中进一步定义(例如 src/lib.rs 可能包含:mod foo { mod bar { pub fn hello() {} } } - 尽管你不能使用 mod foo; 单独在 lib.rs).

main.rs 中,您在 top-level 模块中 crate

mod mod1; 创建一个新模块 mod1,并将 ./mod1.ts 的内容添加到该模块。

所以 ./mod1.rs 中的所有代码都在 crate::mod1 模块中。

当你在./mod1.rs里面调用use mod2时,它看到它在crate::mod1里面,它的精神家园目录是src/mod1,然后寻找:

  • src/mod1/mod2.rs
  • src/mod1/mod2/mod.rs

复杂性来自于允许模块既是目录又是文件,而不是强制每个模块是它自己的目录(可能试图避免 Java 文件夹结构),这会消除歧义。

要记住的关键lib.rsmod.rs特殊的文件,它们的行为与目录中的其他文件。

它们将始终位于 parent 文件夹路径所描述的模块中(例如 src/foo/bar/mod.rs = foo::bar),而所有其他文件都属于它们自己的模块(src/foo/bar/baz.rs = foo::bar::baz).

乡村风格

Rust 对此有一些看法。

不再推荐使用 mod.rs,这很好,因为它具有来自其兄弟姐妹的这种特殊行为。但是lib.rsmain.rs还是比较特别的

如果您想将测试与代码放在一起 (foo.rs + foo_test.rs),建议您不要这样做。我不喜欢这样,所以我使用上面的 path 东西,我认为这对测试很好,因为它们不会导出到任何地方。必须在上面的模块中声明测试感觉不对,我也不喜欢必须使用 foo/test.rs