问题描述
如果你有这样的目录结构:
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:
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");
}
然而,这会产生一个错误:
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"
似乎沿着路径导入,即从 main
到 module1/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
.
推荐答案
我假设你想在顶层声明 utils
和 utils::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 中使用父模块导入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!