我有4个文件:
- 一月一日**
mod bar;
fn main() {
let v = vec![1, 2, 3];
println!("Hello, world!");
}
- 一米一米一**
pub mod foo;
pub mod bar;
- 一米二米一x**
pub fn say_foo() {
}
- 一米三米一x**
use crate::foo;
fn bar() {
foo::say_foo();
}
当我运行cargo run
时,我收到一个错误消息:
error[E0432]: unresolved import `crate::foo`
--> src/bar.rs:1:5
|
1 | use crate::foo;
| ^^^^^^^^^^ no `foo` in the root
有人能给我解释一下如何解决这个问题吗?更广泛地说:当有一个main.rs
和一个lib.rs
时,模块查找是如何工作的?
编辑:将mod foo
添加到main.rs
可以解决这个问题。但是我不明白--我的印象是lib.rs
是"暴露"我所有模块的地方?为什么我还必须在main.rs
中声明模块?
我的Cargo.toml
:
[package]
name = "hello-world"
version = "0.1.0"
authors = ["me@mgail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
4条答案
按热度按时间tpgth1q71#
让我们从头开始,看看The Cargo Book中的Package Layout章节,正如你所看到的,你的软件包可以包含很多东西:
Package 布局
这里并没有列出所有的可能性,只列出了二进制文件/库的组合。
一个二进制
这是一个包含单个二进制文件的包的示例。入口点是
src/main.rs
中的main
函数。Cargo.toml
:src/main.rs
:x一个一个一个一个x一个一个二个x
一个图书馆
这是一个带有库的包的例子。库没有入口点,你不能运行它们。它们被用于功能共享。
Cargo.toml
:src/lib.rs
:您在
Cargo.toml
文件中看到任何关于二进制文件或库的内容了吗?没有。原因是我已经跟踪了Package Layout,cargo
知道在哪里查找内容。二进制文件和库
这是一个包含二进制文件和库的包的示例。
Cargo.toml
:src/lib.rs
:src/main.rs
:同样的问题,您在
Cargo.toml
文件中看到任何关于二进制文件或库的内容了吗?此软件包包含两个内容:
src/main.rs
,入口点src/main.rs::main
),src/lib.rs
,共享代码)。库可以通过
use hallo::...
从二进制文件中引用,其中hallo
是这个包的名称(Cargo.toml
-〉[package]
-〉name
)。你的问题
Cargo.toml
:相同的 Package 布局
库零件
src/lib.rs
:src/foo.rs
:src/bar.rs
:crate
指的是src/lib.rs
,因为我们在库的上下文中。将其视为独立单元,并通过
use hallo::...;
从外部引用它。二进制部分
src/main.rs
:我们只是在用图书馆。
没有图书馆
代码相同,但
lib.rs
已重命名为utils.rs
,并且(foo|bar).rs
文件已移至src/utils/
文件夹。src/utils.rs
:src/utils/foo.rs
:src/utils/bar.rs
:我们也可以在这里使用
crate
,但是因为我们是在二进制文件的上下文中,所以路径不同。src/main.rs
:在这里,我们刚刚声明了另一个模块(
utils
),并且正在使用它。总结
Cargo.toml
含量:如果有一个
src/main.rs
文件,你基本上是这样说的:如果有一个
src/lib.rs
文件,你基本上是这样说的:如果两者都有,你基本上是这么说的:
文件
xmd2e60i2#
简而言之,the official Rust book是这样说的:
如果软件包包含
src/main.rs
和src/lib.rs
,则它有两个板条箱:库和二进制文件,两者都与包同名。此外,Rust的参考文献是这样说的:
crate
解析相对于当前crate的路径因此,您的项目中实际上有两个板条箱,
crate
限定符解析到哪个板条箱取决于您调用它的位置。现在在你的代码示例中,如果你想编译 * 你必须从
src/main.rs
中移除 *mod bar;
,否则你将声明bar
是两个板条箱中的一个模块。在删除它之后,因为在
src/lib.rs
中有:bar
现在将是src/lib.rs
的crate内的模块,因此bar.rs
中的crate
限定符将引用src/lib.rs
的hello-world
crate,这正是您想要的。还有一件事,如果你想从
src/main.rs
访问暴露在src/lib.rs
中的项目,你必须按照@zrzka说的那样做,那就是命名src/lib.rs
和src/main.rs
共享的crate的名称。例如,在你的项目中,命名为hello-world
:是如何将
src/lib.rs
中声明的foo
模块导入到src/main.rs
中。然而,导入行为似乎不能以其他方式工作。也就是说,如果你在
src/main.rs
中声明了一些公共模块,即使你指定了机箱的名称,你也不能将其导入到src/lib.rs
机箱中。我找不到描述这种行为的文档,但通过在Rust 1.37.0中测试,情况似乎确实如此。o75abkj43#
lib.rs
和main.rs
文件是软件包的两个独立入口点。当使用
cargo run
(或者构建二进制文件并显式运行它)时,要使用的入口点是main.rs
,并且crate
关键字引用binary crate,它甚至不必知道lib.rs
中有一些东西:二进制文件将像对待任何其它外部机箱一样对待库,并且必须通过extern crate hello_world
或例如use hello_world::foo
导入库。但是,当您导入库时,入口点是
lib.rs
,而crate
是library crate。在这种情况下,是的,您添加到lib.rs
中的所有内容都将暴露给整个crate。在这种情况下,通常的工作流程是使二进制文件类似于库的一个薄 Package 器-在某些极端情况下,
main.rs
将只包含类似于整个逻辑(以及所有的项目结构)都被放入库的板条箱中。原因之一就是您所遇到的:可能混淆该混凝土模块是否在 Package 中的每个板条箱中进口。
46qrfjad4#
还有一件事
mod
在您的机箱中定义一个新模块,无论是二进制机箱还是库机箱;而use
仅将模块带入当前作用域。在您的示例中,
bar.rs
中的use crate::foo
试图将crate根目录下名为foo
的模块带入作用域,但由于main.rs
中没有mod foo
,因此foo
模块不是二进制crate的一部分。