[英]How do you use parent module imports in 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?您如何使用其他文件中的函数?
From the Rust tutorial, it sounds like I should be able to do this:从 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 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"
It appears that importing down the path, ie from main
to module1/blah.rs
works, and importing peers, ie blah2
from blah
works, but importing from the parent scope doesn't.似乎沿着路径导入,即从main
到module1/blah.rs
工作,并导入对等点,即blah2
从blah
工作,但从父范围导入没有。
If I use the magical #[path]
directive, I can make this work:如果我使用神奇的#[path]
指令,我可以完成这项工作:
blah2.rs blah2.rs
#[path="../utils/logging.rs"]
mod logging;
pub fn doit() {
logging::trace("Blah2 invoked");
}
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?在 Rust 中没有更好的方法来做到这一点吗?
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
.在 Python 中,您将from .blah import x
用于本地范围,但如果您想访问绝对路径,您可以使用from project.namespace.blah import x
。
I'm going to answer this question too, for anyone else who finds this and is (like me) totally confused by the difficult-to-comprehend answers.我也将回答这个问题,对于其他发现这个问题并且(像我一样)被难以理解的答案完全困惑的人。
It boils down to two things I feel are poorly explained in the tutorial:归结为我觉得教程中没有很好解释的两件事:
The mod blah;
mod blah;
syntax imports a file for the compiler.语法为编译器导入一个文件。 You must use this on all the files you want to compile .您必须在要编译的所有文件上使用它。
As well as shared libraries, any local module that is defined can be imported into the current scope using use blah::blah;
除了共享库之外,任何定义的本地模块都可以使用use blah::blah;
导入到当前作用域中use blah::blah;
. .
A typical example would be:一个典型的例子是:
src/main.rs
src/one/one.rs
src/two/two.rs
In this case, you can have code in one.rs
from two.rs
by using use
:在这种情况下,您可以使用use
将代码放在one.rs
的two.rs
:
use two::two; // <-- Imports two::two into the local scope as 'two::'
pub fn bar() {
println!("one");
two::foo();
}
However, main.rs
will have to be something like:但是, 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();
}
Notice that you can use the blah/mod.rs
file to somewhat alleviate the awkwardness, by placing a file like one/mod.rs
, because mod x;
请注意,您可以使用blah/mod.rs
文件,通过放置像one/mod.rs
这样的文件来稍微减轻尴尬,因为mod x;
attempts x.rs
and x/mod.rs
as loads.尝试将x.rs
和x/mod.rs
作为负载。
// one/mod.rs
pub mod one.rs
You can reduce the awkward file imports at the top of main.rs to:您可以将 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();
}
There's an example project doing this on Github .有一个示例项目在Github上执行此操作。
It's worth noting that modules are independent of the files the code blocks are contained in;值得注意的是,模块独立于代码块所在的文件; although it would appear the only way to load a file blah.rs
is to create a module called blah
, you can use the #[path]
to get around this, if you need to for some reason.尽管似乎加载文件blah.rs
的唯一方法是创建一个名为blah
的模块,但如果出于某种原因需要,您可以使用#[path]
来解决此问题。 Unfortunately, it doesn't appear to support wildcards, aggregating functions from multiple files into a top-level module is rather tedious.不幸的是,它似乎不支持通配符,将多个文件中的函数聚合到一个顶级模块中是相当乏味的。
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
.我假设您想在顶层声明utils
和utils::logging
,并且只想在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
.模块的声明是用mod
完成的,它将它插入到 AST 中并定义其规范的foo::bar::baz
样式路径,并且与模块的正常交互(远离声明) 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();
}
The only change I made was the use crate::utils;
我所做的唯一更改是use crate::utils;
line in blah2
(in Rust 2015 you could also use use utils
or use ::utils
). blah2
中的blah2
(在 Rust 2015 中,您也可以使用use utils
或use ::utils
)。 Also see the second half of this answer for more details on how use
works.另请参阅此答案的后半部分,了解有关use
如何工作的更多详细信息。 The relevant section of The Rust Programming Language is a reasonable reference too, in particular these two subsections: The Rust Programming Language的相关部分也是一个合理的参考,特别是这两个小节:
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; }
另外,请注意我写的都是内联的,将foo/bar.rs
的内容foo/bar.rs
放在mod foo { mod bar { <contents> } }
,将其更改为mod foo { mod bar; }
mod foo { mod bar; }
with the relevant file available should be identical. mod foo { mod bar; }
与现有的相关文件应该是相同的。
(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.) (顺便说一句, println(": {}\\n", msg)
打印两个新行; println!
已经包含一个( ln
是“line”),要么print!(": {}\\n", msg)
或println!(": {}", msg)
只打印一个。)
It's not idiomatic to get the exact structure you want, you have to make one change to the location of blah2.rs :获得您想要的确切结构并不是惯用的,您必须对blah2.rs的位置进行一次更改:
src
├── main.rs
├── module1
│ ├── blah
│ │ └── blah2.rs
│ └── blah.rs
└── utils
└── logging.rs
mod utils {
pub mod logging;
}
mod module1 {
pub mod blah;
}
fn main() {
utils::logging::trace("Logging works");
module1::blah::doit();
}
pub fn trace(msg: &str) {
println!(": {}\n", msg);
}
mod blah2;
pub fn doit() {
blah2::doit();
}
// this is the only change
// Rust 2015
// use utils;
// Rust 2018
use crate::utils;
pub fn doit() {
utils::logging::trace("Blah2 invoked");
}
I realize this is a very old post and probably wasn't using 2018. However, this can still be really tricky and I wanted to help those out that were looking.我意识到这是一篇很老的帖子,可能没有使用 2018 年。但是,这仍然非常棘手,我想帮助那些正在寻找的人。
Because Pictures are worth a thousand words I made this simple for code splitting.因为图片值一千个字,所以我把它简化为代码拆分。
Then as you probably guessed they all have an empty pub fn some_function().然后正如您可能猜到的那样,它们都有一个空的 pub fn some_function()。
We can further expand on this via the changes to main我们可以通过更改 main 来进一步扩展这一点
The additional changes to nested_mod对nested_mod 的额外更改
Let's now go back and answer the question: We added blah1 and blah2 to the mod_1 We added a utils with another mod logging inside it that calls some fn's.现在让我们回过头来回答这个问题: 我们将 blah1 和 blah2 添加到 mod_1 我们添加了一个 utils,其中包含另一个调用 fn 的 mod 日志记录。 Our mod_1/mod.rs now contains:我们的 mod_1/mod.rs 现在包含:
pub mod blah.rs
pub mod blah2.rs
We created a utils/mod.rs used in main containing:我们创建了一个用于 main 的 utils/mod.rs 包含:
pub mod logging
Then a directory called logging/with another mod.rs where we can put fns in logging to import.然后是一个名为 logging/ 与另一个 mod.rs 的目录,我们可以在其中将 fns 放入日志中以进行导入。
Source also here https://github.com/DavidWhit/Rust_Modules来源也在这里https://github.com/DavidWhit/Rust_Modules
Also Check Chapters 7 for libs example and 14.3 that further expands splitting with workspaces in the Rust Book.另请查看第 7 章中的 libs 示例和 14.3,它进一步扩展了 Rust Book 中工作空间的拆分。 Good Luck!祝你好运!
If you create a file called mod.rs
, rustc
will look at it when importing a module.如果您创建一个名为mod.rs
的文件, rustc
将在导入模块时查看它。 I would suggest that you create the file src/utils/mod.rs
, and make its contents look something like this:我建议您创建文件src/utils/mod.rs
,并使其内容如下所示:
pub mod logging;
Then, in main.rs
, add a statement like this:然后,在main.rs
,添加如下语句:
use utils::logging;
and call it with并调用它
logging::trace(...);
or you could do或者你可以做
use utils::logging::trace;
...
trace(...);
Basically, declare your module in the mod.rs
file, and use
it in your source files.基本上,在mod.rs
文件中声明你的模块,并在你的源文件中use
它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.