【Rust中的项目管理】

Rust中的项目管理


前言

在开发者进行项目立项并逐步开发时,尤为重要的是项目结构和各个模块的管理,在C++中,通常我们结合文件夹以及namespace和头文件的共同作用下将项目结构变得合理,Rust为开发者提供了一整套管理体系如Package,Crates,Module &use ,Path,通过这些特性来共同管理Rust项目,开合自如。

Package,Crate,Module &use ,Path

package :Cargo Feature,可用于build crate,share create & test Crate。
Crate :Rust编译器可编译的最小块,可编译出二进制文件或者库,crate在写法上便是模块树,包含了一系列具有相关性的代码,通过目录和mod关键字组合而成。
Module &use : 在整个工程中起到组织,限制,控制代码隐私的作用
Path: 描述所需具体模块以及方法所在位置的手段,结合use达到C++中的include 效果。

通过代码示例解释 Crate,Module ,use,Path

创建一个package:

rust 复制代码
cargo new mypackage --lib

可以看到如下的目录结构:

上述便是package的具体表现形式,package允许libraries和execute同时存在,但是在一个package中,只能有一个lib,可以有多个executes,但是不论如何,package一定要包含一个crate,不论是 binary or library。

在省略--lib的状态下, 会在src中直接创建 一个main.rs,加上--lib 创建项目时会在src中创建一个lib.rs ,不论是lib.rs还是main.rs都是crate root,既模块树的树根,抑或是package编译每一个crate的入口root,cargo会将跟文件传递给rustc从而进行编译lib.rs对应与package同名的库,main.rs对应与package同名的二进制可执行文件。

代码组织化

示例工程结构如下:

rust中的模块树如同操作系统中的目录树结构一样,依赖文件夹以及文件夹命名,如图中所示绿色框中的hairs.rs 与文件夹hairs,一般情况下,为了工程代码的整洁,通常不会将所有的代码放在hairs.rs 中,但是需要设计的层级关系,如图中关系,hair->skin->bones,在工程中就可以像图中一样处理,简单来讲 就是子模块放在父模块同级同名文件夹内部,代码文件名xxx.rs在Path 既寻找指定代码依赖时同样重要。 古早的写法:/xxx/xxx/mod.rs现在依然支持但是不再推荐了。可以这样简单的理解,模块名称仅和文件名称、mod xxx 有关,文件夹只是寻路以及整理文件的作用。

skin.rs 中的代码

rust 复制代码
pub mod bones;

pub mod muscle {
    #[derive(Debug)]
    pub struct Muscle {
        pub name: String,
        pub muscle_group: String,
    }
    impl Muscle {
        pub fn new(name: &str, muscle_group: &str) -> Muscle {
            Muscle {
                name: name.to_string(),
                muscle_group: muscle_group.to_string(),
            }
        }
        pub fn get_muscle_group(&self) -> &str {
            &self.muscle_group
        }
        pub fn get_name(&self) -> &str {
            &self.name
        }
    }
}
pub mod fat {
    #[derive(Debug)]
    pub struct Fat {
        pub percentage: f64,
    }
    impl Fat {
        pub fn new(percentage: f64) -> Self {
            Fat { percentage }
        }
        fn get_percentage(&self) -> f64 {
            self.percentage
        }
    }
}

可以看到,在这里我们将bones模块暴露出去,并在skin包内部定义了Muscle 和 Fat 模块以及结构体和方法。

需要注意的是,模块默认的内部全部都是私有化的,所以如果不加上pub,外部无法访问使用。

struct & enum

struct 内部私有,enum内部pub,这是他们的不同之处。

相对路径和绝对路径

与目录结构一样,我们既可以使用绝对路径也可以使用相对路径use 我们需要的模块,如何选择?根据现实情况,当N个module在同一个父模块中,使用super简单快捷, self一般个人不是很喜欢用,当module来源于父模块之外,用绝对路径。对于引用模块中的函数来讲,直接引入函数的父模块更方便,一般情况下你不会仅使用一个模块中的一个方法,除非你的代码出现了什么设计上的问题,但是如果是使用结构体容器之类,那最好是包含到最后一层。

还记得我们再创建工程时生成的lib.rs吗?来看看其内部代码:

rust 复制代码
mod Body;
pub mod body;
pub mod cloths;
pub mod hairs;
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);
    }
}

这里的use super::*;便是使用模块中的所有子模块,为了unit test,关于uint test ,已经在Rust中的测试一章细聊过。

引用同名模块怎么办?

Rust中,你可以在使用时用全路径,亦或使用as 起个别名,具体的,这没有约定俗成的建议,完全取决于开发者的习惯。

代码示例:

rust 复制代码
use std::io::Result as IoResult;

use

代码示例:

rust 复制代码
use mypackage::{body, cloths::Cloths, hairs::skin::muscle::Muscle};
fn main() {
    let hair_color = Muscle::new("kangkang", "groupOne");
    println!("{:?}", hair_color.get_muscle_group());

    let cloth = Cloths::new("skirt", "yellow");
    println!("{:?}", cloth.get_name());

    let mybody = body::Body::new();
    mybody.show();
}
rust 复制代码
use crate::hairs::skin::bones;
use crate::hairs::skin::{fat, muscle};
#[derive(Debug)]
pub struct Body {
    my_bones: bones::Bones,
    my_fat: fat::Fat,
    my_muscle: muscle::Muscle,
}

impl Body {
    pub fn new() -> Self {
        Body {
            my_bones: bones::Bones::new("humanBones", 206),
            my_fat: fat::Fat::new(15.0),
            my_muscle: muscle::Muscle::new("muscle", "arms"),
        }
    }

    pub fn show(&self) {
        println!("{:?}", &self);
    }
}

pub use

这里既是开放使用某个模块,使用它相当于开发者在使用处直接"创建"了这个模块,在使用时便只需引用到使用处的模块即可,这多数用在我们自己编写crate时候,由于封装性我们将很多数据结构封装的很深,而使用方又不得不使用,而我们又不想暴露更多细节给到用户,尤其是module层级较深时,对于使用者也是一个难题,pub use便可以很好的解决这样的问题。

"每天怎么过,都是我们的选择"

相关推荐
汉克老师15 分钟前
GESP4级考试语法知识(贪心算法(四))
开发语言·c++·算法·贪心算法·图论·1024程序员节
爱吃生蚝的于勒1 小时前
C语言最简单的扫雷实现(解析加原码)
c语言·开发语言·学习·计算机网络·算法·游戏程序·关卡设计
Ai 编码助手1 小时前
Go语言 实现将中文转化为拼音
开发语言·后端·golang
hummhumm1 小时前
第 12 章 - Go语言 方法
java·开发语言·javascript·后端·python·sql·golang
hummhumm1 小时前
第 8 章 - Go语言 数组与切片
java·开发语言·javascript·python·sql·golang·database
何曾参静谧1 小时前
「QT」文件类 之 QDir 目录类
开发语言·qt
何曾参静谧1 小时前
「QT」文件类 之 QTemporaryDir 临时目录类
开发语言·qt
杜杜的man1 小时前
【go从零单排】Directories、Temporary Files and Directories目录和临时目录、临时文件
开发语言·后端·golang
qq_308957471 小时前
Gin 框架入门(GO)-1
开发语言·golang·gin
杨荧2 小时前
【JAVA毕业设计】基于Vue和SpringBoot的宠物咖啡馆平台
java·开发语言·jvm·vue.js·spring boot·spring cloud·开源