我希望有一个模块包含多个struct,* 每个struct都在自己的文件中。* 以Math
模块为例:
Math/
Vector.rs
Matrix.rs
Complex.rs
我希望每个结构体都在同一个模块中,我将从主文件中使用该模块,如下所示:
use Math::Vector;
fn main() {
// ...
}
然而Rust的模块系统(一开始有点混乱)并没有提供一个明显的方法来做到这一点。它似乎只允许你把你的整个模块放在一个文件中。这是不是不质朴?如果不是,我该怎么做?
7条答案
按热度按时间watbbzwu1#
Rust的模块系统实际上非常灵活,可以让你公开任何你想要的结构,同时隐藏你的代码在文件中的结构。
我认为这里的关键是使用
pub use
,它允许您从其他模块重新导出标识符,在Rust的std::io
机箱中有这样的先例,其中子模块中的一些类型被重新导出以在std::io
中使用。编辑(2019年8月25日):答案的以下部分是很久以前写的。它解释了如何单独使用
rustc
设置这样一个模块结构。今天,人们通常会使用Cargo来处理大多数用例。虽然以下部分仍然有效,但它的某些部分(例如#![crate_type = ...]
)可能看起来很奇怪。这不是推荐的解决方案。为了适应您的示例,我们可以从以下目录结构开始:
下面是您的
main.rs
:您的
src/lib.rs
:最后,
src/vector.rs
:这就是奇迹发生的地方,我们定义了一个子模块
math::vector::vector_a
,它实现了一种特殊的向量,但是我们不希望库的客户端关心是否存在vector_a
子模块,相反,我们希望在math::vector
模块中提供它,这是通过pub use self::vector_a::VectorA
实现的,其重新导出当前模块中的vector_a::VectorA
标识符。但是你问到如何将特殊的向量实现放到不同的文件中,这就是
mod vector_b;
行所做的,它指示Rust编译器为该模块的实现寻找vector_b.rs
文件,果然,这就是我们的src/vector_b.rs
文件:从客户端的Angular 来看,
VectorA
和VectorB
是在两个不同的模块和两个不同的文件中定义的,这是完全不透明的。如果您与
main.rs
位于同一个目录中,您应该能够使用以下命令运行它:总的来说,Rust书中的X11E1F1X还是相当不错的,有很多例子。
最后,Rust编译器还会自动查找子目录。例如,上面的代码将在以下目录结构中工作:
编译和运行的命令也保持不变。
3vpjnl9f2#
Rust模块规则包括:
1.源文件只是它自己的模块(特殊文件main.rs、lib.rs和mod.rs除外)。
1.目录只是模块路径组件。
1.文件 mod.rs只是目录的模块。
math目录下的matrix.rs1文件就是
math::matrix
模块,这很简单,你在文件系统上看到的东西,也可以在源代码中找到,这是文件路径和模块路径的一一对应关系。所以你可以用
use math::matrix::Matrix
导入一个结构体Matrix
,因为这个结构体在matrix.rsmath目录下的www.example.com文件中。不满意吗?你更喜欢use math::Matrix;
,不是吗?这是可能的。用以下命令重新导出math/ www.example.com中的标识符x1m4 n1mod.rsx:还有一个步骤可以让它工作。Rust需要一个模块声明来load模块。在main.rs中添加一个
mod math;
。如果你不这样做,在导入时你会从编译器中得到一个错误消息,如下所示:这里的提示是误导性的。没有必要使用额外的板条箱,除非您确实打算编写一个单独的库。
将此添加到www.example.com的顶部main.rs:
对于子模块
vector
、matrix
和complex
,模块声明也是必需的,因为math
需要加载它们才能重新导出它们。标识符的重新导出仅在加载了标识符的模块时才有效。这意味着,要重新导出标识符math::matrix::Matrix
,您需要写入mod matrix;
。您可以在math/mod.rs中执行此操作。因此,请创建包含以下内容的文件:你就完了。
1源文件名在Rust中通常以小写字母开头,这就是我使用matrix.rs而不是Matrix.rs的原因。
2 Java不同。你用
package
声明路径,也是。这是多余的。路径已经从源文件在文件系统中的位置明显。为什么要在文件顶部的声明中重复这些信息呢?当然,有时快速浏览源代码比找出文件的文件系统位置更容易。我能理解人们说'It“没那么令人困惑。6kkfgxo03#
Rusts纯粹主义者可能会称我为异教徒,并讨厌这个解决方案,但这要简单得多:只需在其自己的文件中执行每项操作,然后使用www.example.com中的“include!“宏mod.rs:
这样你就不会得到额外的嵌套模块,避免了复杂的导出和重写规则。简单,有效,没有麻烦。
n8ghc7c14#
好吧,我和编译器斗争了一段时间,终于让它工作了(感谢BurntSushi指出
pub use
。main.rs:
数学mod.rs:
数学vector.rs
其他结构体也可以用同样的方式添加。用0.9编译,而不是master。
xmq68pz95#
我想在这里添加如何包括Rust文件时,他们是深嵌套。我有以下结构:
如何从
main.rs
访问sink.rs
或toilet.rs
?正如其他人所提到的,Rust不知道文件。相反,它把所有东西都看作模块和子模块。要访问浴室目录中的文件,你需要导出它们或把它们放在顶部。你可以通过指定一个文件名和你想访问的目录以及文件中的
pub mod filename_inside_the_dir_without_rs_ext
来完成这一点。例如。
1.在
home
目录中创建名为bathroom.rs
的文件:1.导出文件名:
1.在
main.rs
旁边创建名为home.rs
的文件pub mod
www.example.com文件 bathroom.rs file1.在
main.rs
范围内也可以使用
use
语句:在子模块中包括其他兄弟模块(文件)
如果您希望使用
toilet.rs
中的sink.rs
,则可以通过指定self
或super
关键字来调用该模块。最终目录结构
你最终会得到这样的结果:
上面的结构只适用于Rust 2018以后的版本。下面的目录结构也适用于2018,但它是2015以前的工作方式。
其中
home/mod.rs
与./home.rs
相同,home/bathroom/mod.rs
与home/bathroom.rs
相同。Rust做了这个修改,因为如果你包含一个与目录同名的文件,编译器会感到困惑。2018版本(最先显示的那个)修复了这个结构。有关详细信息,请参见this repo;有关总体说明,请参见此YouTube video。
最后一件事...避免使用连字符!使用
snake_case
代替。重要提示
你必须把所有的文件都放在最上面,即使顶层文件不需要深层文件。
这意味着,对于
sink.rs
,要发现toilet.rs
,您需要使用上面的方法来桶它们,一直到main.rs
!换句话说,在
toilet.rs
中执行pub mod sink;
或use self::sink;
将 * 不起作用 *,除非您一直将它们暴露到main.rs
!因此,永远记得桶你的文件到顶部!
hmae6n7t6#
导出模块的一个更简单的方法,我从Github中学到的。
1cklez4t7#
调整问题的示例目录和文件名以符合Rust命名约定:
确保导出
math
目录下每个文件中的公共符号(类型、函数等),方法是在它们前面加上关键字pub
。定义
math.rs
:上面的文件保持
math
的子模块私有,但是子模块的公共符号从模块math
导出,这有效地扁平化了模块结构。在
main.rs
中使用math::Vector
: