[rust]项目结构

58 阅读5分钟

包(package)

默认创建一个二进制package,package其实就是一个项目,是cargo的一个功能,允许我们创建,测试和分享crate

➜  rust cargo new hello_rust
    Creating binary (application) `hello_rust` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
➜  rust cd hello_rust
➜  hello_rust git:(master) ✗ tree
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files
➜  hello_rust git:(master) ✗

小结:

  1. 我们通过cargo创建的hello_rust就是一个二进制package
  2. 输出Creating binary (application) hello_rust package
  3. 约定俗成:cargo的惯例是以src/main.rs作为二进制包的根文件,也即作为程序的入口。该文件编译之后的名字和我们创建的package名字相同,也为hello_rust,所有的代码都是从该文件的main函数开始执行

可执行package

编译并运行:

➜  hello_rust git:(master) ✗ cargo run
   Compiling hello_rust v0.1.0 (/Users/liukunlong/rust/hello_rust)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.85s
     Running `target/debug/hello_rust`
Hello, world!
➜  hello_rust git:(master) ✗

查看编译后的目录结构:

  1. 会看到有一个名为hello_rust的二进制文件
  2. 直接运行它,也会直接输出hello, world
➜  hello_rust git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    ├── CACHEDIR.TAG
    └── debug
        ├── build
        ├── deps
        │   ├── hello_rust-47671166f4c95115
        │   ├── hello_rust-47671166f4c95115.0wekr9jbnot8e5m7k1zy6am5l.rcgu.o
        │   ├── hello_rust-47671166f4c95115.5bnqosv9dxgdsdvjuoirftlt6.rcgu.o
        │   ├── hello_rust-47671166f4c95115.5s7u4chpxl2hsjkqizh33o3et.rcgu.o
        │   ├── hello_rust-47671166f4c95115.7f9y7pvlcp57vkocwa494mxv4.rcgu.o
        │   ├── hello_rust-47671166f4c95115.byzvs0pkajy0ewugsiwdw4e8w.rcgu.o
        │   ├── hello_rust-47671166f4c95115.d
        │   └── hello_rust-47671166f4c95115.de52o0skguo6qnp0eo10uvgp1.rcgu.o
        ├── examples
        ├── hello_rust
        ├── hello_rust.d
        └── incremental
            └── hello_rust-275zygvnlq6ng
                ├── s-gzqwa8ndyk-1274bf2-1z8u6kagyer666gu5h78mrm7n
                │   ├── 0wekr9jbnot8e5m7k1zy6am5l.o
                │   ├── 5bnqosv9dxgdsdvjuoirftlt6.o
                │   ├── 5s7u4chpxl2hsjkqizh33o3et.o
                │   ├── 7f9y7pvlcp57vkocwa494mxv4.o
                │   ├── byzvs0pkajy0ewugsiwdw4e8w.o
                │   ├── de52o0skguo6qnp0eo10uvgp1.o
                │   ├── dep-graph.bin
                │   ├── query-cache.bin
                │   └── work-products.bin
                └── s-gzqwa8ndyk-1274bf2.lock

9 directories, 24 files
➜  hello_rust git:(master) ✗ cd target/debugdebug git:(master) ✗ ll
total 920
drwxr-xr-x   2 bytedance  staff    64B  9  8 22:31 build
drwxr-xr-x  10 bytedance  staff   320B  9  8 22:31 deps
drwxr-xr-x   2 bytedance  staff    64B  9  8 22:31 examples
-rwxr-xr-x   1 bytedance  staff   454K  9  8 22:31 hello_rust
-rw-r--r--   1 bytedance  staff   105B  9  8 22:31 hello_rust.d
drwxr-xr-x   3 bytedance  staff    96B  9  8 22:31 incremental
➜  debug git:(master) ✗ ./hello_rust
Hello, world!
➜  debug git:(master) ✗

库package

创建一个库package

➜  rust cargo new lib_rust --lib
    Creating library `lib_rust` package
note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
➜  rust cd lib_rust
➜  lib_rust git:(master) ✗ tree
.
├── Cargo.toml
└── src
    └── lib.rs

1 directory, 2 files
➜  lib_rust git:(master) ✗ cargo run
error: a bin target must be available for `cargo run`
➜  lib_rust git:(master) ✗ cargo build
   Compiling lib_rust v0.1.0 (/Users/liukunlong/rust/lib_rust)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.36s
➜  lib_rust git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── lib.rs
└── target
    ├── CACHEDIR.TAG
    └── debug
        ├── build
        ├── deps
        │   ├── lib_rust-1b5c3fee316f2a85.1ewmc71fglnteipcah3q7t2tb.rcgu.o
        │   ├── lib_rust-1b5c3fee316f2a85.d
        │   ├── liblib_rust-1b5c3fee316f2a85.rlib
        │   └── liblib_rust-1b5c3fee316f2a85.rmeta
        ├── examples
        ├── incremental
        │   └── lib_rust-1yrg9bmycp8cm
        │       ├── s-gzqx1i1ou2-1hzo10j-94qpry6tczyhtwoc2zbqn7xto
        │       │   ├── 1ewmc71fglnteipcah3q7t2tb.o
        │       │   ├── dep-graph.bin
        │       │   ├── query-cache.bin
        │       │   └── work-products.bin
        │       └── s-gzqx1i1ou2-1hzo10j.lock
        ├── liblib_rust.d
        └── liblib_rust.rlib

9 directories, 15 files
➜  lib_rust git:(master) ✗

小结:

  1. 通过cargo指定--lib参数创建的就是一个库package
  2. 输出Creating library lib_rust package
  3. 和二进制package不同的是,对库package执行cargo run会报错,因为库package只能作为三方库被其他项目引用
  4. 约定俗成:与src/main.rs类似,该库package的根文件是src/lib.rs
  5. 约定俗成:执行cargo build后,会生成两个liblib_rust文件,因为是库crate,所以叫lib,package叫lib_rust,所以文件名就叫liblib_rust

Crate

可执行crate

对于之前创建的hello_rust项目,该项目下的src/main.rs就是一个可执行的crate,可以通过rustc来编译

rust cd hello_rusthello_rust git:(master) ✗ cd srcsrc git:(master) ✗ rustc main.rssrc git:(master) ✗ ll
total 912
-rwxr-xr-x  1 bytedance  staff   451K  9  8 22:51 main
-rw-r--r--  1 bytedance  staff    45B  9  8 22:22 main.rssrc git:(master) ✗ ./main
Hello, world!
➜  src git:(master) ✗ tree
.
├── main
└── main.rs

0 directories, 2 filessrc git:(master) ✗ 

库crate

对于之前创建的hello_rust项目,该项目下的src/lib.rs就是一个库crate。库crate没有main函数,它们不会被编译为可执行文件,仅提供一些诸如函数之类的,可供其他项目调用的东西

➜  rust cd lib_rust
➜  lib_rust git:(master) ✗ cd src
➜  src git:(master) ✗ cat lib.rs
pub fn add(left: u64, right: u64) -> u64 {
    left + right
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}
➜  src git:(master) ✗

包和crate的关系

  1. 一个package只包含0或1个库crate
  2. 一个package可包含任意多个可执行crate
  3. 一个package至少包含一个库crate或可执行crate

那么如果有两个或多个可执行crate,编译器怎么知道该执行哪一个呢?

模块(module)

一个crate可以有多个module,通过mod关键字声明module

定义module

module里面可以嵌套module

mod zoo {
    pub fn hello() {
        println!("welcome to Beijing Zoo")
    }

    pub mod land_animals {
        pub fn dog_say() {
            println!("wang wang")
        }

        pub fn duck_say() {
            println!("ga ga")
        }
    }
}

调用module

fn main() {
    zoo::hello();
    zoo::land_animals::dog_say();
    zoo::land_animals::duck_say();
}

module间互相调用

  1. 通过super关键字调用父级方法
  2. 通过self关键字调用自身方法
mod zoo {
    pub fn hello() {
        println!("welcome to Beijing Zoo")
    }

    pub mod land_animals {
        // 和鹦鹉聊天
        pub fn parrot_talk() {
            super::hello();
        }
        
        // 鹦鹉的叫声
        pub fn parrot_say() {
            println!("ga ga")
        }

        // "我”的叫声
        pub fn i_say() {
            self::parrot_say();
        }
    }
}

不同crate中mod调用

➜  hello_rust git:(master) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── america.rs
│   ├── main.rs
│   └── other
│       └── mod.rs
  1. 在main.rs同级目录下创建america.rs,之后在main.rs中引入america module即可使用
  2. 在main.rs同级目录下创建一个文件夹,而通过文件夹的方式后创建的文件名则必须为mod.rs,之后在main.other module即可使用
  3. 不同crate引用要声明pub才允许访问
// src/america.rs
// src/other/mod.rs
pub fn say_good() {
    println!("welcome to USA zoo")
}
pub mod other;
pub mod america;

fn main() {
    other::say_good();
    say_good();
}

调用库中的module

lib默认的名字和package的名字一样,直接使用package的名字就可以调用库crate中的函数

// src/lib.rs
pub fn lib_hello() {
    println!("lib hello")
}
// src/main.rs
fn main() {
    lib_hello();
}