[英]Rust modules confusion when there is main.rs and lib.rs
I have 4 files:我有4个文件:
main.rs
mod bar;
fn main() {
let v = vec![1, 2, 3];
println!("Hello, world!");
}
lib.rs
pub mod foo;
pub mod bar;
foo.rs
pub fn say_foo() {
}
bar.rs
use crate::foo;
fn bar() {
foo::say_foo();
}
When I run cargo run
I get an error saying:当我运行
cargo run
我收到一条错误消息:
error[E0432]: unresolved import `crate::foo`
--> src/bar.rs:1:5
|
1 | use crate::foo;
| ^^^^^^^^^^ no `foo` in the root
Could someone explain to me how to fix this?有人可以向我解释如何解决这个问题吗? A bit more broadly: how does module lookup work when there's a
main.rs
and a lib.rs
?有点更广泛:如何做模块查找工作时,有一个
main.rs
和lib.rs
?
Edit: Adding mod foo
to main.rs
fixes the issue.编辑:将
mod foo
添加到main.rs
解决了这个问题。 But I don't understand this -- I was under the impression the lib.rs
was the place that "exposed" all of my modules?但我不明白这一点——我的印象是
lib.rs
是“暴露”我所有模块的地方? Why do I have to declare the module in main.rs
as well?为什么我还必须在
main.rs
声明模块?
My Cargo.toml
:我的
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]
Let's start from the beginning.让我们从头开始。 Look at the Package Layout chapter in The Cargo Book .
查看货物手册中的包裹布局章节。 As you can see, your package can contain lot of stuff:
如您所见,您的包可以包含很多东西:
Not all of the possibilities are listed here, just the binary / library combinations.此处未列出所有可能性,仅列出二进制/库组合。
This is an example of a package with single binary.这是一个带有单个二进制文件的包示例。 Entry point is the
main
function in the src/main.rs
.入口点是
src/main.rs
的main
函数。
Cargo.toml
: Cargo.toml
:
[package]
name = "hallo"
version = "0.1.0"
edition = "2018"
src/main.rs
: src/main.rs
:
fn main() {
println!("Hallo, Rust here!")
}
$ cargo run
Hallo, Rust here!
This is an example of a package with a library.这是带有库的包的示例。 Libraries don't have entry points, you can't run them.
图书馆没有入口点,你不能运行它们。 They're used for functionality sharing.
它们用于功能共享。
Cargo.toml
: Cargo.toml
:
[package]
name = "hallo"
version = "0.1.0"
edition = "2018"
src/lib.rs
: src/lib.rs
:
pub fn foo() {
println!("Hallo, Rust library here!")
}
$ cargo run
error: a bin target must be available for `cargo run`
Do you see anything in the Cargo.toml
file about a binary or a library?您是否在
Cargo.toml
文件中看到有关二进制文件或库的任何内容? No. The reason is that I've followed the Package Layout and the cargo
knows where to look for things.不会。原因是我遵循了包裹布局,
cargo
知道去哪里找东西。
This is an example of a package with a binary and a library.这是一个包含二进制文件和库的包示例。
Cargo.toml
: Cargo.toml
:
[package]
name = "hallo"
version = "0.1.0"
edition = "2018"
src/lib.rs
: src/lib.rs
:
pub const GREETING: &'static str = "Hallo, Rust library here!";
src/main.rs
: src/main.rs
:
use hallo::GREETING;
fn main() {
println!("{}", GREETING);
}
Same question, do you see anything in the Cargo.toml
file about a binary or a library?同样的问题,您是否在
Cargo.toml
文件中看到有关二进制文件或库的任何内容? No.不。
This package contains two things:这个包包含两件事:
src/main.rs
, entry point src/main.rs::main
),src/main.rs
,入口点src/main.rs::main
),src/lib.rs
, shared code).src/lib.rs
,共享代码)。 A library can be referenced from the binary via use hallo::...
where the hallo
is this package name ( Cargo.toml
-> [package]
-> name
).数据库可以从二进制通过引用
use hallo::...
其中hallo
是这个包名称( Cargo.toml
- > [package]
- > name
)。
Cargo.toml
: Cargo.toml
:
[package]
name = "hallo"
version = "0.1.0"
edition = "2018"
src/lib.rs
: src/lib.rs
:
pub mod bar;
pub mod foo;
src/foo.rs
: src/foo.rs
:
pub fn say_foo() {
println!("Foo");
}
src/bar.rs
: src/bar.rs
:
use crate::foo;
pub fn bar() {
foo::say_foo();
}
crate
refers to src/lib.rs
, because we're in the context of our library here. crate
指的是src/lib.rs
,因为我们在这里处于我们库的上下文中。
Treat it as a standalone unit and refer to it via use hallo::...;
将其视为一个独立的单元,并通过
use hallo::...;
来引用它use hallo::...;
from the outside world.来自外部世界。
src/main.rs
: src/main.rs
:
use hallo::bar::bar;
fn main() {
bar();
}
Here we're just using our library.在这里,我们只是使用我们的库。
Same code, but lib.rs
was renamed to utils.rs
and (foo|bar).rs
files were moved to the src/utils/
folder.相同的代码,但
lib.rs
被重命名为utils.rs
并且(foo|bar).rs
文件被移动到src/utils/
文件夹。
src/utils.rs
: src/utils.rs
:
pub mod bar;
pub mod foo;
src/utils/foo.rs
: src/utils/foo.rs
:
pub fn say_foo() {
println!("Foo");
}
src/utils/bar.rs
: src/utils/bar.rs
:
use super::foo;
// or use crate::utils::foo;
pub fn bar() {
foo::say_foo();
}
We can use crate
here as well, but because we're in the context of our binary, the path differs.我们也可以在这里使用
crate
,但是因为我们在二进制文件的上下文中,所以路径不同。
src/main.rs
: src/main.rs
:
use utils::bar::bar;
mod utils;
fn main() {
bar();
}
Here we just declared another module ( utils
) and we're using it.在这里,我们刚刚声明了另一个模块(
utils
)并且我们正在使用它。
Cargo.toml
content: Cargo.toml
内容:
[package]
name = "hallo"
version = "0.1.0"
edition = "2018"
If there's a src/main.rs
file, you're basically saying this:如果有一个
src/main.rs
文件,你基本上是这样说的:
[package]
name = "hallo"
version = "0.1.0"
edition = "2018"
[[bin]]
name = "hallo"
src = "src/main.rs"
If there's a src/lib.rs
file, you're basically saying this:如果有一个
src/lib.rs
文件,你基本上是这样说的:
[package]
name = "hallo"
version = "0.1.0"
edition = "2018"
[lib]
name = "hallo"
path = "src/lib.rs"
If there're both of them, you're basically saying this:如果两者都有,你基本上是这样说的:
[package]
name = "hallo"
version = "0.1.0"
edition = "2018"
[[bin]]
name = "hallo"
path = "src/main.rs"
[lib]
name = "hallo"
path = "src/lib.rs"
In shortthe official Rust book has this to say:简而言之,Rust 官方书是这样说的:
If a package contains
src/main.rs
andsrc/lib.rs
, it has two crates: a library and a binary, both with the same name as the package.如果一个包包含
src/main.rs
和src/lib.rs
,它有两个 crate:一个库和一个二进制文件,两者都与包同名。
Furthermore the Rust reference says this:此外,Rust 参考文献说:
crate
resolves the path relative to the current cratecrate
解析相对于当前 crate 的路径
So there are actually two crates in your project, and to which crate the crate
qualifier resolves to depends on where you call it.因此,您的项目中实际上有两个 crate,并且
crate
限定符解析到哪个 crate 取决于您调用它的位置。
Now in your code example, if you want things to compile you have to remove mod bar;
现在在你的代码示例中,如果你想要编译你必须删除
mod bar;
from src/main.rs
.来自
src/main.rs
。 Otherwise you'll be declaring that bar
is a module within two crates.否则,您将声明
bar
是两个板条箱中的模块。
After you remove that, then because in src/lib.rs
you had:删除它之后,因为在
src/lib.rs
你有:
pub mod foo;
pub mod bar;
bar
would now be a module within src/lib.rs
's crate, so the crate
qualifier in bar.rs
would then refer to src/lib.rs
's hello-world
crate, which is what you want. bar
现在将成为src/lib.rs
的 crate 中的一个模块,因此bar.rs
的crate
限定符将引用src/lib.rs
的hello-world
crate,这就是您想要的。
One more thing, if you wanted to access items that are exposed in src/lib.rs
from src/main.rs
, you have to do as @zrzka said, which is to name the name of the crate that both src/lib.rs
and src/main.rs
share.还有一件事,如果你想被暴露访问项目
src/lib.rs
从src/main.rs
,你必须为@zrzka说,这是命名的箱子,这两个的名字做src/lib.rs
和src/main.rs
共享。 For example, in your project which is named hello-world
:例如,在您名为
hello-world
:
use hello_world::foo;
fn main() {
foo::say_foo();
}
is how you import the foo
module declared in src/lib.rs
into src/main.rs
.是你如何导入
foo
中声明模块src/lib.rs
到src/main.rs
。
However it does appear that the importing behavior doesn't work the other way.然而,导入行为似乎并没有以其他方式工作。 Ie if you declare some public module in
src/main.rs
, you can't import it into the src/lib.rs
crate even when you specify the name of the crate.也就是说,如果你在
src/main.rs
声明了一些公共模块,即使你指定了包的名称,你也不能将它导入到src/lib.rs
包中。 I couldn't find documentation describing this behavior but by testing it in Rust 1.37.0, it does appear to be the case.我找不到描述此行为的文档,但通过在 Rust 1.37.0 中对其进行测试,情况似乎确实如此。
The lib.rs
and main.rs
files are two independent entry points for your package.该
lib.rs
和main.rs
文件是你的包两个独立的入口点。
When you use cargo run
(or build the binary and run it explicitly), the entry point to be used is main.rs
, and the crate
keyword refer to the binary crate .当您使用
cargo run
(或构建二进制文件并显式运行它)时,要使用的入口点是main.rs
,并且crate
关键字指的是二进制 crate 。 It doesn't even have to know that there is something in lib.rs
: the binary will treat the library as it would any other external crate, and it must be imported, through extern crate hello_world
or, for example, use hello_world::foo
.它甚至不必知道
lib.rs
中有什么东西:二进制文件会像对待任何其他外部 crate 一样对待库,并且必须通过extern crate hello_world
或例如use hello_world::foo
导入它use hello_world::foo
。
When you import the library, however, the entry point is lib.rs
, and the crate
is the library crate .但是,当您导入库时,入口点是
lib.rs
,而crate
是库 crate 。 In this case, yes, all that you've added to lib.rs
is exposed to the whole crate.在这种情况下,是的,您添加到
lib.rs
所有lib.rs
都暴露在整个 crate 中。
The usual worksflow in this case is to make the binary something like a thin wrapper around the library - in some extreme cases the main.rs
would only contain something like在这种情况下,通常的工作流程是使二进制文件类似于库周围的薄包装 - 在某些极端情况下,
main.rs
将只包含类似
use library;
fn main() {
library::main();
}
and the whole logic (and all the project structure) goes into the library crate.整个逻辑(以及所有项目结构)都进入了库箱。 One of the reasons is exactly what you've run into: the possible confusion whether this concrete module is imported in each crate in the package.
原因之一正是您遇到的情况:可能会混淆是否在包中的每个板条箱中导入此具体模块。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.