Skip to content

模块化编程

  • 模块(module)
  • 箱(crate)
  • 包(package)
  • 工作空间(workspace)

箱(crate)

箱是一个独立的可编译单元,它编译后会生成一个可执行文件或者一个库。

箱可以包含多个模块,每个模块可以包含多个文件。

  • 可执行箱:必须有一个 main 函数来定义程序的执行入口
  • 库箱:没有 main 函数,不会被编译为可执行程序。
    • 编译库箱,使用 rustc --crate-type=lib 参数

注意:箱之间不能存在循环依赖

rust
pub fn public_function() {
    println!("public_function");
}
fn private_function() {
    println!("private_function");
}
pub fn indirect_access() {
    println!("indirect_access");
    private_function();
}
bash
rustc --crate-type=lib myfunc.rs
// libmyfunc.rlib
// 生成的文件名必须lib开头,否则会报错
rust
fn main() {
    println!("main");
    myfunc::indirect_access();
    myfunc::public_function();
    
    // 无法访问私有函数
    // myfunc::private_function();
//  |           ^^^^^^^^^^^^^^^^ private function
}
bash
rustc --extern myfunc=libmyfunc.rlib main.rs --edition=2021
./main
# ➜  src git:(master) ✗ ./main
#main222
#indirect_access
#private_function
#public_function
#➜  src git:(master) ✗

命令参考:

--crate-type:编译器生成包的类型列表

指示rustc要构建的crate类型。该标志接受逗号分隔的值列表,并且可以多次指定。有效的crate类型为:

  • lib—生成编译器首选的库类型,当前默认为 rlib。
  • rlib — Rust静态库。
  • staticlib —原生静态库。
  • dylib — Rust动态库。
  • cdylib —原生动态库。
  • bin —可运行的可执行程序。
  • proc-macro —生成适合于程序宏类库的格式,该格式可由编译器加载。

包(package)

包(package)用于项目级管理,包中可以包含多个箱。

一个包会包含一个 Cargo.toml 文件,该文件描述了包信息,包括箱名称、版本、依赖项等。

包中可以包含最多一个库箱(library crate),多个可执行箱(binary crate)。但是必须至少包含一个箱。

bash
cargo new --bin my_project
bash
  my_project git:(master)  tree 
.
├── Cargo.toml
└── src
    └── main.rs

2 directories, 2 files
  my_project git:(master) 
bash
cargo run
bash
cargo build
bash
cargo new --lib my_lib
bash
  my_lib git:(master)  tree
.
├── Cargo.toml
└── src
    └── lib.rs

2 directories, 2 files
  my_lib git:(master) 
toml
[lib]
name = "my_lib"
crate-type = ["rlib", "cdylib", "staticlib"]
toml
[package]
name = "my_lib"
version = "0.1.0"
edition = "2021"

[dependencies]
# 引用其他库
mylib= { path = "../mylib" }

[lib]
name = "my_lib"
crate-type = ["rlib", "cdylib", "staticlib"]
bash
cargo build

Rust支持的库有以下几种

  • rlib:Rust库(默认)只能被Rust调用
  • dylib:Rust动态链接库,Windows上编译成.dll文件,Linux上编译成.so文件,也只能被Rust调用
  • cdylib:满足C语言规范的动态链接库,可以被其他语言调用
  • staticlib:静态库,windows上编译成.lib文件,linux上编译成.a文件,可以被其他语言调用。

文件尺寸对比

bash
  my_lib git:(master)  ll -lh target/debug
total 29624
drwxr-xr-x   2 thomas  staff    64B Nov  3 02:00 build
drwxr-xr-x  37 thomas  staff   1.2K Nov  3 02:07 deps
drwxr-xr-x   2 thomas  staff    64B Nov  3 02:00 examples
drwxr-xr-x   6 thomas  staff   192B Nov  3 02:07 incremental
-rw-r--r--   1 thomas  staff    14M Nov  3 02:07 libmy_lib.a
-rw-r--r--   1 thomas  staff    98B Nov  3 02:00 libmy_lib.d
-rwxr-xr-x   1 thomas  staff    16K Nov  3 02:07 libmy_lib.dylib
-rw-r--r--   1 thomas  staff   5.6K Nov  3 02:07 libmy_lib.rlib

包管理工具Cargo

bash
cargo new my_project
bash
cargo run
bash
cargo check
bash
cargo build --release
bash
cargo clean

典型的包结构

bash
  firstrust git:(master)  tree 
.
├── Cargo.lock
├── Cargo.toml
├── benches     # 基准性能测试
│   └── simple_bench.rs
├── examples    # 项目示例
│   └── simple_example.rs
├── src         # 源文件
│   ├── bin   #  其余二进制包
│   │   ├── main1.rs
│   │   └── main2.rs
│   ├── lib.rs    # 唯一库包
│   └── main.rs   # 默认二进制包
└── tests       # 集成测试
    └── some_test.rs

6 directories, 9 files
  firstrust git:(master) 

多个入口函数,指定入口函数

bash
cargo run --bin main2

引用外部库

https://crates.io/

bash
cargo add rand
toml
[dependencies]
rand = "0.8.5"
rust
extern crate rand;

use rand::random;

fn main() {
    for i in 0..10 {
        let x = random::<i32>();
        println!("{}: {}", i, x)
    }
}

打开本地命令

rust
use std::process::Command;

fn main() {
    Command::new("ls")
        .args(&["-lh", "/usr"])
        .status().unwrap();
}

模块

模块是项目中的代码组织方式,Rust使用 mod 关键字来定义模块。

rust
mod mymod {
    pub fn foo() {
        println!("foo");
    }
}
fn main() {
    mymod::foo();
}
rust
mod mymod {
    pub fn foo() {
        println!("foo");
    }
}

use mymod::foo;

fn main() {
    foo();
}
rust
mod mymod {

    // 模块外不可见
    pub const MSG: &'static str = "Hello";

    // 模块内的字模块可见
    pub(self) const MSG2: &'static str = "Hello2";

    // 整个 crate 可见
    pub(crate) const MSG3: &'static str = "Hello3";

    pub mod inner {
        pub fn foo() {
            println!("foo {}", super::MSG2);
        }
    }
}

fn main() {
    println!("{}", mymod::MSG);
    mymod::inner::foo();
    println!("{}", mymod::MSG3);
}

人生感悟