你如何在Rust中使用父模块导入?

时间:2014-01-04 14:17:15

标签: rust

如果你有这样的目录结构:

src/main.rs
src/module1/blah.rs
src/module1/blah2.rs
src/utils/logging.rs

如何使用其他文件中的函数?

从Rust教程中,听起来我应该能够做到这一点:

main.rs

mod utils { pub mod logging; }
mod module1 { pub mod blah; }

fn main() {
    utils::logging::trace("Logging works");
    module1::blah::doit();
}

logging.rs

pub fn trace(msg: &str) {
    println!(": {}\n", msg);
}

blah.rs

mod blah2;
pub fn doit() {
    blah2::doit();
}

blah2.rs

mod utils { pub mod logging; }
pub fn doit() {
    utils::logging::trace("Blah2 invoked");
}

然而,这会产生错误:

error[E0583]: file not found for module `logging`
 --> src/main.rs:1:21
  |
1 | mod utils { pub mod logging; }
  |                     ^^^^^^^
  |
  = help: name the file either logging.rs or logging/mod.rs inside the directory "src/utils"

似乎导入路径,即从mainmodule1/blah.rs工作,导入对等,即blah2blah起作用,但从父作用域导入没有。

如果我使用神奇的#[path]指令,我可以做到这一点:

blah2.rs

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

pub fn doit() {
    logging::trace("Blah2 invoked");
}

我是否真的必须手动使用相对文件路径从父作用域级别导入内容?在Rust中没有更好的方法吗?

在Python中,您使用from .blah import x作为本地范围,但如果要访问绝对路径,可以使用from project.namespace.blah import x

4 个答案:

答案 0 :(得分:26)

我也会回答这个问题,对于那些发现这个问题并且(像我一样)完全被难以理解的答案搞糊涂的人来说。

归结为我觉得在教程中解释不好的两件事:

  • mod blah;语法导入编译器的文件。您必须在要编译的所有文件上使用此功能

  • 除了共享库之外,可以使用use blah::blah;将定义的任何本地模块导入当前作用域。

一个典型的例子是:

src/main.rs
src/one/one.rs
src/two/two.rs

在这种情况下,您可以使用one.rstwo.rs获取use中的代码:

use two::two;  // <-- Imports two::two into the local scope as 'two::'

pub fn bar() {
    println!("one");
    two::foo();
}

但是,main.rs必须是:

use one::one::bar;        // <-- Use one::one::bar 
mod one { pub mod one; }  // <-- Awkwardly import one.rs as a file to compile.

// Notice how we have to awkwardly import two/two.rs even though we don't
// actually use it in this file; if we don't, then the compiler will never
// load it, and one/one.rs will be unable to resolve two::two.
mod two { pub mod two; }  

fn main() {
    bar();
}

请注意,通过放置blah/mod.rs这样的文件,您可以使用one/mod.rs文件稍微缓解尴尬,因为mod x;尝试x.rsx/mod.rs作为负载。

// one/mod.rs
pub mod one.rs

您可以将main.rs顶部的笨拙文件导入减少到:

use one::one::bar;       
mod one; // <-- Loads one/mod.rs, which loads one/one.rs.
mod two; // <-- This is still awkward since we don't two, but unavoidable.    

fn main() {
    bar();
}

有一个示例项目在Github上执行此操作。

值得注意的是,模块独立于代码块所包含的文件;虽然看起来加载文件blah.rs的唯一方法是创建一个名为blah的模块,但如果出于某种原因需要,可以使用#[path]来解决这个问题。不幸的是,它似乎不支持通配符,将多个文件中的函数聚合到顶级模块中相当繁琐。

答案 1 :(得分:25)

我假设您要在顶层声明utilsutils::logging,并希望在module1::blah::blah2内调用它们中的函数。模块的声明是使用mod完成的,它将它插入AST并定义其规范的foo::bar::baz - 样式路径,并且使用{{与模块进行正常交互(远离声明) 1}}。

use

我所做的唯一更改是// main.rs mod utils { pub mod logging { // could be placed in utils/logging.rs pub fn trace(msg: &str) { println!(": {}\n", msg); } } } mod module1 { pub mod blah { // in module1/blah.rs mod blah2 { // in module1/blah2.rs // *** this line is the key, to bring utils into scope *** use utils; pub fn doit() { utils::logging::trace("Blah2 invoked"); } } pub fn doit() { blah2::doit(); } } } fn main() { utils::logging::trace("Logging works"); module1::blah::doit(); } 中的use utils行。有关blah2工作原理的详细信息,另请参阅the second half of this answerrelevant section of The Rust Programming Language也是一个合理的参考,特别是这两个小节:

另外,请注意我全部内联编写,将use的内容直接放在foo/bar.rs中,将其更改为mod foo { mod bar { <contents> } },相关文件应该相同。

(顺便说一下,mod foo { mod bar; }会打印两个新行; println(": {}\n", msg)包含一行(println!为“行”),ln或{{1}只打印一个。)


获得您想要的确切结构:

main.rs

print!(": {}\n", msg)

utils的/ logging.rs

println!(": {}", msg)

模块1 / blah.rs

mod utils {
    pub mod logging;
}

mod module1 {
    pub mod blah;
}

fn main() {
    utils::logging::trace("Logging works");
    module1::blah::doit();
}

module1 / blah2.rs(唯一需要更改的文件)

pub fn trace(msg: &str) { 
    println!(": {}\n", msg); 
}

答案 2 :(得分:1)

我意识到这是一篇很旧的帖子,可能没有使用 2018 年。但是,这仍然非常棘手,我想帮助那些正在寻找的人。

因为图片值一千个字,所以我把它简化为代码拆分。

enter image description here

enter image description here

然后正如您可能猜到的那样,它们都有一个空的 pub fn some_function()。

我们可以通过对 main 的更改进一步扩展 enter image description here

enter image description here

nested_mod 的额外变化 enter image description here

现在让我们回过头来回答这个问题: 我们将 blah1 和 blah2 添加到 mod_1 我们添加了一个 utils,其中包含另一个调用 fn 的 mod 日志记录。 我们的 mod_1/mod.rs 现在包含:

pub mod blah.rs
pub mod blah2.rs

我们创建了一个用于主要包含的 utils/mod.rs:

pub mod logging

然后是一个名为 logging/ 的目录和另一个 mod.rs,我们可以在其中将 fns 放入 logging 中以进行导入。

enter image description here

来源也在这里https://github.com/DavidWhit/Rust_Modules

另请查看第 7 章中的 libs 示例和 14.3,它进一步扩展了 Rust Book 中工作空间的拆分。祝你好运!

答案 3 :(得分:0)

如果您创建名为mod.rs的文件,rustc会在导入模块时查看它。我建议您创建文件src/utils/mod.rs,并使其内容看起来像这样:

pub mod logging;

然后,在main.rs中,添加如下语句:

use utils::logging;

并用

调用它
logging::trace(...);

或者你可以做到

use utils::logging::trace;

...

trace(...);

基本上,在mod.rs文件中声明您的模块,在源文件中声明use

相关问题