如果你有这样的目录结构:
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"
似乎导入路径,即从main
到module1/blah.rs
工作,导入对等,即blah2
从blah
起作用,但从父作用域导入没有。
如果我使用神奇的#[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
。
答案 0 :(得分:26)
我也会回答这个问题,对于那些发现这个问题并且(像我一样)完全被难以理解的答案搞糊涂的人来说。
归结为我觉得在教程中解释不好的两件事:
mod blah;
语法导入编译器的文件。您必须在要编译的所有文件上使用此功能。
除了共享库之外,可以使用use blah::blah;
将定义的任何本地模块导入当前作用域。
一个典型的例子是:
src/main.rs
src/one/one.rs
src/two/two.rs
在这种情况下,您可以使用one.rs
从two.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.rs
和x/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)
我假设您要在顶层声明utils
和utils::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 answer。 relevant 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}只打印一个。)
获得您想要的确切结构:
print!(": {}\n", msg)
println!(": {}", msg)
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);
}
答案 2 :(得分:1)
我意识到这是一篇很旧的帖子,可能没有使用 2018 年。但是,这仍然非常棘手,我想帮助那些正在寻找的人。
因为图片值一千个字,所以我把它简化为代码拆分。
然后正如您可能猜到的那样,它们都有一个空的 pub fn some_function()。
现在让我们回过头来回答这个问题: 我们将 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 中以进行导入。
来源也在这里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
。