当存在www.example.com和www.example.com时,生 rust 模块混淆main.rslib.rs

6qfn3psc  于 2023-03-08  发布在  其他
关注(0)|答案(4)|浏览(152)

我有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]
tpgth1q7

tpgth1q71#

让我们从头开始,看看The Cargo Book中的Package Layout章节,正如你所看到的,你的软件包可以包含很多东西:

  • 一个二进制文件(可以运行的文件)或多个二进制文件,
  • 单个库(共享代码),
  • 实施例,
  • 基准,
  • 集成测试。

Package 布局

这里并没有列出所有的可能性,只列出了二进制文件/库的组合。
一个二进制
这是一个包含单个二进制文件的包的示例。入口点是src/main.rs中的main函数。
Cargo.toml

[package]
name = "hallo"
version = "0.1.0"
edition = "2018"

src/main.rs
x一个一个一个一个x一个一个二个x

一个图书馆

这是一个带有库的包的例子。库没有入口点,你不能运行它们。它们被用于功能共享。
Cargo.toml

[package]
name = "hallo"
version = "0.1.0"
edition = "2018"

src/lib.rs

pub fn foo() {
    println!("Hallo, Rust library here!")
}
$ cargo run
error: a bin target must be available for `cargo run`

您在Cargo.toml文件中看到任何关于二进制文件或库的内容了吗?没有。原因是我已经跟踪了Package Layoutcargo知道在哪里查找内容。

二进制文件和库

这是一个包含二进制文件和库的包的示例。
Cargo.toml

[package]
name = "hallo"
version = "0.1.0"
edition = "2018"

src/lib.rs

pub const GREETING: &'static str = "Hallo, Rust library here!";

src/main.rs

use hallo::GREETING;

fn main() {
    println!("{}", GREETING);
}

同样的问题,您在Cargo.toml文件中看到任何关于二进制文件或库的内容了吗?
此软件包包含两个内容:

  • 二进制(根src/main.rs,入口点src/main.rs::main),
  • 库(根src/lib.rs,共享代码)。

库可以通过use hallo::...从二进制文件中引用,其中hallo是这个包的名称(Cargo.toml-〉[package]-〉name)。
你的问题
Cargo.toml

[package]
name = "hallo"
version = "0.1.0"
edition = "2018"

相同的 Package 布局

库零件

src/lib.rs

pub mod bar;
pub mod foo;

src/foo.rs

pub fn say_foo() {
    println!("Foo");
}

src/bar.rs

use crate::foo;

pub fn bar() {
    foo::say_foo();
}

crate指的是src/lib.rs,因为我们在库的上下文中。
将其视为独立单元,并通过use hallo::...;从外部引用它。

二进制部分

src/main.rs

use hallo::bar::bar;

fn main() {
    bar();
}

我们只是在用图书馆。

没有图书馆

代码相同,但lib.rs已重命名为utils.rs,并且(foo|bar).rs文件已移至src/utils/文件夹。
src/utils.rs

pub mod bar;
pub mod foo;

src/utils/foo.rs

pub fn say_foo() {
    println!("Foo");
}

src/utils/bar.rs

use super::foo;
// or use crate::utils::foo;

pub fn bar() {
    foo::say_foo();
}

我们也可以在这里使用crate,但是因为我们是在二进制文件的上下文中,所以路径不同。
src/main.rs

use utils::bar::bar;

mod utils;

fn main() {
    bar();
}

在这里,我们刚刚声明了另一个模块(utils),并且正在使用它。

总结

Cargo.toml含量:

[package]
name = "hallo"
version = "0.1.0"
edition = "2018"

如果有一个src/main.rs文件,你基本上是这样说的:

[package]
name = "hallo"
version = "0.1.0"
edition = "2018"

[[bin]]
name = "hallo"
src = "src/main.rs"

如果有一个src/lib.rs文件,你基本上是这样说的:

[package]
name = "hallo"
version = "0.1.0"
edition = "2018"

[lib]
name = "hallo"
path = "src/lib.rs"

如果两者都有,你基本上是这么说的:

[package]
name = "hallo"
version = "0.1.0"
edition = "2018"

[[bin]]
name = "hallo"
path = "src/main.rs"

[lib]
name = "hallo"
path = "src/lib.rs"

文件

xmd2e60i

xmd2e60i2#

简而言之,the official Rust book是这样说的:
如果软件包包含src/main.rssrc/lib.rs,则它有两个板条箱:库和二进制文件,两者都与包同名。
此外,Rust的参考文献是这样说的:
crate解析相对于当前crate的路径
因此,您的项目中实际上有两个板条箱,crate限定符解析到哪个板条箱取决于您调用它的位置。
现在在你的代码示例中,如果你想编译 * 你必须从src/main.rs中移除 * mod bar;,否则你将声明bar是两个板条箱中的一个模块。
在删除它之后,因为在src/lib.rs中有:

pub mod foo;
pub mod bar;

bar现在将是src/lib.rs的crate内的模块,因此bar.rs中的crate限定符将引用src/lib.rshello-world crate,这正是您想要的。
还有一件事,如果你想从src/main.rs访问暴露在src/lib.rs中的项目,你必须按照@zrzka说的那样做,那就是命名src/lib.rssrc/main.rs共享的crate的名称。例如,在你的项目中,命名为hello-world

use hello_world::foo;
fn main() {
    foo::say_foo();
}

是如何将src/lib.rs中声明的foo模块导入到src/main.rs中。
然而,导入行为似乎不能以其他方式工作。也就是说,如果你在src/main.rs中声明了一些公共模块,即使你指定了机箱的名称,你也不能将其导入到src/lib.rs机箱中。我找不到描述这种行为的文档,但通过在Rust 1.37.0中测试,情况似乎确实如此。

o75abkj4

o75abkj43#

lib.rsmain.rs文件是软件包的两个独立入口点。
当使用cargo run(或者构建二进制文件并显式运行它)时,要使用的入口点是main.rs,并且crate关键字引用binary crate,它甚至不必知道lib.rs中有一些东西:二进制文件将像对待任何其它外部机箱一样对待库,并且必须通过extern crate hello_world或例如use hello_world::foo导入库。
但是,当您导入库时,入口点是lib.rs,而cratelibrary crate。在这种情况下,是的,您添加到lib.rs中的所有内容都将暴露给整个crate。
在这种情况下,通常的工作流程是使二进制文件类似于库的一个薄 Package 器-在某些极端情况下,main.rs将只包含类似于

fn main() {
    library::main();
}

整个逻辑(以及所有的项目结构)都被放入库的板条箱中。原因之一就是您所遇到的:可能混淆该混凝土模块是否在 Package 中的每个板条箱中进口。

46qrfjad

46qrfjad4#

还有一件事mod在您的机箱中定义一个新模块,无论是二进制机箱还是库机箱;而use仅将模块带入当前作用域。
在您的示例中,bar.rs中的use crate::foo试图将crate根目录下名为foo的模块带入作用域,但由于main.rs中没有mod foo,因此foo模块不是二进制crate的一部分。

相关问题