本文介绍了你如何在 Rust 中使用父模块导入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

If you have a directory structure like this:

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

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

How do you use functions from other files?

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

From the Rust tutorial, it sounds like I should be able to do this:

ma​​in.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");
}

然而,这会产生一个错误:

However, this produces an error:

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 工作,并导入对等点,即 blah2 fromblah 有效,但从父作用域导入无效.

It appears that importing down the path, i.e. from main to module1/blah.rs works, and importing peers, i.e. blah2 from blah works, but importing from the parent scope doesn't.

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

If I use the magical #[path] directive, I can make this work:

blah2.rs

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

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

我真的必须手动使用相对文件路径从父范围级别导入内容吗?在 Rust 中没有更好的方法来做到这一点吗?

Do I really have to manually use relative file paths to import something from a parent scope level? Isn't there some better way of doing this in Rust?

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

In Python, you use from .blah import x for the local scope, but if you want to access an absolute path you can use from project.namespace.blah import x.

推荐答案

我假设你想在顶层声明 utilsutils::logging,并且只想在 module1::blah::blah2 中从它们调用函数.模块的声明是用 mod 完成的,它将它插入到 AST 中并定义其规范的 foo::bar::baz 样式路径,以及与模块(远离声明)使用 use 完成.

I'm assuming you want to declare utils and utils::logging at the top level, and just wish to call functions from them inside module1::blah::blah2. The declaration of a module is done with mod, which inserts it into the AST and defines its canonical foo::bar::baz-style path, and normal interactions with a module (away from the declaration) are done with 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 crate::utils;

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

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

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

我所做的唯一更改是 blah2 中的 use crate::utils; 行(在 Rust 2015 中,您也可以使用 use utils 使用 ::utils).另请参阅本答案的后半部分 有关 use 工作原理的更多详细信息.相关部分The Rust Programming Language 也是一个合理的参考,特别是这两个小节:

The only change I made was the use crate::utils; line in blah2 (in Rust 2015 you could also use use utils or use ::utils). Also see the second half of this answer for more details on how use works. The relevant section of The Rust Programming Language is a reasonable reference too, in particular these two subsections:

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

Also, notice that I write it all inline, placing the contents of foo/bar.rs in mod foo { mod bar { <contents> } } directly, changing this to mod foo { mod bar; } with the relevant file available should be identical.

(顺便说一下,println(": {}\n", msg) 打印了两行;println! 已经包含了一行(ln 是 "line"),要么 print!(": {}\n", msg) 要么 println!(": {}", msg)只打印一个.)

(By the way, println(": {}\n", msg) prints two new lines; println! includes one already (the ln is "line"), either print!(": {}\n", msg) or println!(": {}", msg) print only one.)

获得您想要的确切结构并不习惯,您必须对 blah2.rs 的位置进行一次更改:

It's not idiomatic to get the exact structure you want, you have to make one change to the location of blah2.rs:

src
├── main.rs
├── module1
│   ├── blah
│   │   └── blah2.rs
│   └── blah.rs
└── utils
    └── logging.rs

main.rs

mod utils {
    pub mod logging;
}

mod module1 {
    pub mod blah;
}

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

utils/logging.rs

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

module1/blah.rs

mod blah2;

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

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

// this is the only change

// Rust 2015
// use utils;

// Rust 2018
use crate::utils;

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

这篇关于你如何在 Rust 中使用父模块导入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-23 06:15
查看更多