前沿
这是 rust 开发环境搭建的第二篇,深入理解 rust 项目的组织结构,掌握 cargo 等工具的使用,是进入 rust programming 世界的关键步骤。
Cargo 项目结构
Cargo 是 rust 用来管理项目的核心工具,所有的 rust 项目都是基于 cargo 工具来构建的,下面是一个只包含最核心目录和文件的一个组织结构:
.
├── Cargo.lock
├── Cargo.toml
├── src
│ ├── bin
│ │ └── another_executable.rs
│ ├── lib.rs
│ └── main.rs
├── benches
│ └── large-input.rs
├── examples
│ └── simple.rs
└── tests
└── some-integration-tests.rs
解释:
src 目录中存放所有的 rust 源码
src/lib.rs 是默认的库文件入口代码
src/main.rs 是默认的可执行文件入口代码
编译所生成的可执行文件的实现代码都在 src/bin/*.rs 中
后面三个目录 benches/, examples/, tests/ 都是辅助开发的一些源码目录,大型项目完整性需要。
参考这里
注意,引用某个 mod 时(比如 something),可以是 something.rs 或 something/mod.rs,这有点类似 lua 中的引用方式。
src/something.rs
pub trait Foo {
fn method(&self) -> String;
}
impl Foo for u8 {
fn method(&self) -> String { format!("u8: {}", *self) }
}
impl Foo for String {
fn method(&self) -> String { format!("string: {}", *self) }
}
src/main.rs
mod something;
use crate::something::*;
fn do_something<T: Foo>(x :T) {
x.method();
}
fn main() {
let x = 5u8;
let y = "Hello ".to_string();
do_something(x);
do_something(y);
}
解释:
src/lib.rs 和 src/main.rs 都是对外的,两者不互相关联和引用,这两个文件名是固定的,不要改动。
如果想要多模块开发,比如 main.rs 中有些函数想独立出来文件,那么就新建一些文件或目录,比如,把函数移动到 something.rs 中去,然后,这个文件就作为一个 mod,想要在 main.rs 中引用 something.rs 中的函数时,在 main.rs 文件中做两步:
(1)声明要使用的 module 名字,如下: mod something;
(2)声明要使用的 module 中的那些函数,如下: use crate::something::*;
同样,src/lib.rs 也是对外的,因此,它只需要做第一步就可以,但因为是要对外提供接口,因此 lib.rs 中一定要加 pub。
pub mod something
记住:
src/main.rs 不要引用 src/lib.rs 文件。因为他们都是提供对外访问的,一个提供 library,一个提供 binary,彼此之间是独立的,无任何依赖关系。
当然,如果你不需要提供 libaray,那么你可以不创建 lib.rs。由于 lib.rs 是对外提供的,所以 subdirectory 也可以用 use crate::something 来访问。
src 下的目录结构:兄弟、父、子三个层级
crate root 很重要,他就是项目的根目录,所有人都可以引用根目录下的 crate。
use 语句与 C++ 的语句作用相同,作用就是:rename and bring into scope
简单来说就是,使用了 use 之后,可以免去前缀来使用了,比如:
C++ 中
没使用 use 语句之前:
std::cout << "hello world!" << std::endl;
使用了 use 语句之后:
use std;
cout << "hello world!" << endl;
同理,rust 中
enum Status {
Rich,
Poor,
}
fn main() {
use Status::{Poor, Rich};
//let status = Status::Poor;//无需显示的加上作用域Status
let status = Poor;
}
或
pub mod a
{
pub mod b
{
pub fn function()
{
println!("This is a::b::function");
}
pub fn other_funtion()
{
println!("This is a::b::other_funtion");
}
}
}
use a::b as ab;
use a::b::other_funtion as ab_other_funtion;
fn main()
{
ab::function();
ab::other_funtion();
ab_other_funtion();
}
注意: 需要很好的理解 mod 关键词的 rename 含义,也就是说,当你使用 pub mod xxx 时,你其实是对一个模块命名了,命名之后,你就可以使用 use crate::xxx::func1 或 use self:xxx:func1 这种方式了;而如果没有使用 pub mod xxx 的话,那么你就只能使用 use crate::filename::func1 来引用了,如果这个 filename 是有多级目录的话,会很麻烦(路径会很长),所以,使用 mod 就可以把一个目录下所有的子目录都定义成一个 module,这样,引用的时候路径就简化了。
比如有一个 project 结构如下:
// 1)a.rs
pub fn a_echo(){
println!("a_echo!");
//(2)c.rs
注意,这里 crate 不能用 self
use crate::src_a::a::*;
pub fn c_echo(){
println!("c_echo!");
a_echo();
}
// (3) b.rs
use crate::src_a::a_echo;
pub fn b_echo(){
println!("b_echo! => call a()!");
a_echo();
}
// (4) src_a.rs
pub mod a;
pub mod c;
pub use a::*;
pub use c::*;
// (5) src_b.rs
pub mod b;
pub use b::*;
// (6) main.rs
crate 和 self 可以互相替代。
pub mod src_a;
pub mod src_b;
pub use self::src_a::*;
pub use crate::src_b::*;
fn main() {
println!("Hello, world!");
src_a::a_echo();
src_b::b_echo();
}
可以看到,src_a.rs 和 src_b.rs 的作用就是把内部的两个文件定义成一个 mod 了,这样,在上层 parent 的文件就可以方便引用了。 参考:blog.csdn.net/wowotuo/art…
- 可以用 use crate:: 把 absolute path 引入
mod sound {
pub mod instrument {
pub fn clarinet() {
// Function body code goes here
}
}
}
use crate::sound::instrument;
fn main() {
instrument::clarinet();
instrument::clarinet();
instrument::clarinet();
}
- 也可以用 use self:: 把 relative path 引入
mod sound {
pub mod instrument {
pub fn clarinet() {
// Function body code goes here
}
}
}
use self::sound::instrument;
fn main() {
instrument::clarinet();
instrument::clarinet();
instrument::clarinet();
}
ABSOLUTE VS RELATIVE PATHS WITH “USE” :
mod sound {
pub mod instrument {
pub fn clarinet() {
// Function body code goes here
}
}
}
mod performance_group {
use crate::sound::instrument;
pub fn clarinet_trio() {
instrument::clarinet();
instrument::clarinet();
instrument::clarinet();
}
}
fn main() {
performance_group::clarinet_trio();
}
mod 与 C++ 中的 namespace 关键词相同作用,用来定义一个作用域 区别在于,C++ 中 namespace 是在原文件中定义使用,而 rust 则可以在引用的文件中使用。
相关参考:
全文完!
如果你喜欢我的文章,欢迎关注我的微信公众号:codeandroad