30·工程化入门

模块系统

模块系统

学习目标

  1. 理解模块和可见性
  2. 掌握 use 引入
  3. 理解文件系统与模块的关系
  4. 掌握 pubpub(crate) 等可见性控制

核心概念

模块定义

mod math {
    pub fn add(a: i32, b: i32) -> i32 {
        a + b
    }

    pub fn subtract(a: i32, b: i32) -> i32 {
        a - b
    }

    // 私有函数
    fn internal_helper() -> i32 {
        42
    }

    pub mod advanced {
        pub fn power(base: i32, exp: u32) -> i32 {
            (0..exp).fold(1, |acc, _| acc * base)
        }
    }
}

fn main() {
    println!("{}", math::add(1, 2));
    println!("{}", math::advanced::power(2, 10));
    // math::internal_helper();  // ❌ 私有
}

可见性

mod outer {
    pub mod inner {
        pub fn public_fn() {}      // 公开
        fn private_fn() {}         // 模块内私有
        pub(crate) fn crate_fn() {} // crate 内公开
        pub(super) fn parent_fn() {} // 父模块可见
    }

    fn test() {
        inner::public_fn();       // ✅
        inner::private_fn();      // ✅ 同模块
        inner::crate_fn();        // ✅ 同 crate
        inner::parent_fn();       // ✅ 父模块
    }
}

use 引入

mod shapes {
    pub struct Circle {
        pub radius: f64,
    }

    impl Circle {
        pub fn new(radius: f64) -> Self {
            Circle { radius }
        }

        pub fn area(&self) -> f64 {
            std::f64::consts::PI * self.radius * self.radius
        }
    }

    pub mod utils {
        pub fn diameter(radius: f64) -> f64 {
            radius * 2.0
        }
    }
}

// 引入方式
use shapes::Circle;
use shapes::utils::diameter;
use shapes::{Circle, utils};  // 多个引入

fn main() {
    let c = Circle::new(5.0);
    println!("直径: {}", diameter(c.radius));
    println!("面积: {}", c.area());
}

文件系统模块

src/
├── main.rs         // mod math; 声明
├── math/
│   ├── mod.rs      // pub fn add() ...
│   ├── basic.rs    // pub fn subtract() ...
│   └── advanced.rs // pub fn power() ...
// src/main.rs
mod math;

fn main() {
    math::add(1, 2);
    math::basic::subtract(2, 1);
}

// src/math/mod.rs
pub mod basic;
pub mod advanced;

// src/math/basic.rs
pub fn subtract(a: i32, b: i32) -> i32 { a - b }

重导出

mod internal {
    pub mod utils {
        pub fn helper() {}
    }
}

// 重导出:让用户不需要知道内部结构
pub use internal::utils::helper;

fn main() {
    // 直接用,不需要 internal::utils::helper()
    helper();
}

use as 重命名

use std::collections::HashMap as Map;
use std::io::Result as IoResult;

fn main() {
    let mut map: Map<String, i32> = Map::new();
    map.insert("key".to_string(), 42);
}

实践练习

练习 1:组织代码

// 模拟文件结构
mod database {
    pub mod connection {
        pub struct Connection {
            pub url: String,
        }
        impl Connection {
            pub fn new(url: &str) -> Self {
                Connection { url: String::from(url) }
            }
        }
    }

    pub mod query {
        pub fn select(table: &str) -> String {
            format!("SELECT * FROM {}", table)
        }
    }
}

use database::connection::Connection;
use database::query::select;

fn main() {
    let conn = Connection::new("postgres://localhost/db");
    println!("连接: {}", conn.url);
    println!("查询: {}", select("users"));
}

练习 2:库结构

// 模拟一个库的公开 API
mod mylib {
    // 内部实现
    mod internal {
        pub fn process(data: &str) -> String {
            data.to_uppercase()
        }
    }

    // 公开 API
    pub fn transform(input: &str) -> String {
        internal::process(input)
    }

    pub struct Transformer {
        prefix: String,
    }

    impl Transformer {
        pub fn new(prefix: &str) -> Self {
            Transformer { prefix: String::from(prefix) }
        }

        pub fn apply(&self, input: &str) -> String {
            format!("{}: {}", self.prefix, internal::process(input))
        }
    }
}

fn main() {
    println!("{}", mylib::transform("hello"));
    let t = mylib::Transformer::new("Result");
    println!("{}", t.apply("world"));
}

常见错误

1. 忘记 pub

mod mymod {
    fn helper() {}  // 私有
}
// mymod::helper();  // ❌ 私有函数不可访问

2. 路径错误

mod a {
    mod b {
        pub fn hello() {}
    }
}
// b::hello();  // ❌
// a::b::hello();  // ✅

小结

概念说明
mod声明/定义模块
pub公开可见性
pub(crate)crate 内可见
pub(super)父模块可见
use引入路径
use ... as ...重命名
pub use重导出

练习编辑器

rust
Loading...