zoukankan      html  css  js  c++  java
  • rust 模块组织结构

    rust有自己的规则和约定用来组织模块,比如一个包最多可以有一个库crate,任意多个二进制crate、导入文件夹内的模块的两种约定方式... 知道这些约定,就可以快速了解rust的模块系统。
    先把一些术语说明一下:

    • 是cargo的一个功能,当执行cargo new xxxx的时候就是创建了一个包。
    • crate是二进制或者库项目。rust约定在Cargo.toml的同级目录下包含src目录并且包含main.rs文件,就是与包同名的二进制crate,如果包目录中包含src/lib.rs,就是与包同名的crate。包内可以有多crate,多个crates就是一个模块的树形结构。如果一个包内同时包含src/main.rssrc/lib.rs,那么他就有两个crate,如果想有多个二进制craterust约定需要将文件放在src/bin目录下,每个文件就是一个单独的crate
    • crate根用来描述如何构建crate的文件。比如src/main.rs或者src/lib.rs就是crate根crate根文件将由Cargo传递给rustc来实际构建库或者二进制项目。
    • 带有Cargo.toml文件的包用来描述如何构建crate,一个包可以最多有一个库crate,任意多个二进制crate

    github 代码地址

    模块

    模块以mod开头,下面创建了一个say模块

    mod say {
        pub fn hello() {
            println!("Hello, world!");
        }
    }
    

    需要注意的是模块内,所有的项(函数、方法、结构体、枚举、模块和常量)默认都是私有的,可以用pub将项变为公有,上面的代码里pub fn hello()就是把函数hello()变为公有的。
    子模块可以通过super访问父模块中所有的代码,包括私有代码。但是父模块中的代码不能访问子模块中的私有代码。

    mod say {
        pub fn hello() {
            println!("Hello, world!");
        }
        fn hello_2() {
            println!("hello")
        }
        pub mod hi {
            pub fn hi_1() {
                super::hello_2();
            }
            pub fn hi_2() {
                println!("hi there");
            }
        }
    }
    

    同一文件内的模块

    同一文件内的模块,最外层的mod say不用设置为pub就可以访问,但是mod say下面的要设置成pub才可以访问。

    fn main() {
        // 相对路径
        say::hello();
        // 绝对路径调用
        crate::say::hello();
        
        say::hi::hi_1();
        say::hi::hi_2();
    }
    
    mod say {
        pub fn hello() {
            println!("Hello, world!");
        }
        fn hello_2() {
            println!("hello")
        }
        pub mod hi {
            pub fn hi_1() {
                super::hello_2();
            }
            pub fn hi_2() {
                println!("hi there");
            }
        }
    }
    

    调用模块内的方法,可以使用绝对路径以crate开头,也就是从crate根开始查找,say模块定义在crate根 src/main.rs中,所以就可以这么调用crate::say::hello();绝对路径类似于Shell中使用/从文件系统根开始查找文件。
    相对路径以模块名开始say,他定义于main()函数相同的模块中,类似Shell在当前目录开始查找指定文件say/hello

    mod hi是一个嵌套模块,使用时要写比较长say::hi::hi_2();,可以使用use将名称引入作用域。

    use crate::say::hi;
    
    fn main() {
        // 相对路径
        say::hello();
        // 绝对路径调用
        crate::say::hello();
    
        // 不使用 use
        say::hi::hi_1();
        say::hi::hi_2();
        // 使用 use 后就可以这么调用
        hi::hi_1();
    }
    

    使用pub use 重导出名称

    不同的模块之前使用use引入,默认也是私有的。如果希望调用的模块内use引用的模块,就要用pub公开,也叫重导出

    fn main() {
        // 重导出名称
        people::hi::hi_1();
        people::hello();
        // 但是不能 
        // people::say::hello();
    }
    
    mod say {
        pub fn hello() {
            println!("Hello, world!");
        }
        fn hello_2() {
            println!("hello")
        }
        pub mod hi {
            pub fn hi_1() {
                super::hello_2();
            }
            pub fn hi_2() {
                println!("hi there");
            }
        }
    }
    
    mod people {
        // 重导出名称
        pub use crate::say::hi;
        use crate::say;
        pub fn hello() {
            say::hello();
        }
    }
    

    如果想都导出自己和嵌入的指定包可以用self,例mod people_2 把模块people和嵌套模块info全部导出来了。

    use crate::say::hi;
    
    fn main() {
        // 相对路径
        say::hello();
        // 绝对路径调用
        crate::say::hello();
    
        // 不使用 use
        say::hi::hi_1();
        say::hi::hi_2();
        // 使用 use 后就可以这么调用
        hi::hi_1();
    
        // 重导出名称
        people::hi::hi_1();
        people::hello();
        // 但是不能 
        // people::say::hello();
    
        people_2::people::hello();
        people_2::info::name();
    }
    
    mod say {
        pub fn hello() {
            println!("Hello, world!");
        }
        fn hello_2() {
            println!("hello")
        }
        pub mod hi {
            pub fn hi_1() {
                super::hello_2();
            }
            pub fn hi_2() {
                println!("hi there");
            }
        }
    }
    
    pub mod people {
        // 重导出名称
        pub use crate::say::hi;
        use crate::say;
        pub fn hello() {
            say::hello();
        }
        pub mod info {
            pub fn name() {
                println!("zhangsang");
            }
        }
    }
    
    
    mod people_2 {
        // 重导出名称
        pub use crate::people::{self, info};
        pub fn hello() {
            info::name();
        }
    }
    
    

    不同文件夹的引用

    方式一

    看一下目录结构:

    rust的约定,在目录下使用mod.rs将模块导出。
    看一下user.rs的代码:

    #[derive(Debug)]
    pub struct User {
        name: String,
        age: i32
    }
    
    impl User {
        pub fn new_user(name: String, age: i32) -> User {
            User{
                name,
                age
            }
        }
        pub fn name(&self) -> &str {
            &self.name
        }
    }
    
    pub fn add(x: i32, y: i32) -> i32 {
        x + y 
    }
    

    然后在mod.rs里导出:

    pub mod user;
    

    main.rs调用

    mod user_info;
    use user_info::user::User;
    
    fn main() {
        let u1 = User::new_user(String::from("tom"), 5);
        println!("user name: {}", u1.name());
        println!("1+2: {}", user_info::user::add(1, 2));
    }
    
    

    方式二

    看一下目录结构

    和上面的不同之前是。这种方式是user_info目录里没有mod.rs,但是在外面有一个user_info.rs
    user_info.rs中使用pub mod user;是告诉Rust在另一个与模块同名的文件夹内(user_info文件夹)内加载模块user。这也是rust的一个约定,但比较推荐用上面的方式。
    代码和上面是一样的。
    user.rs

    #[derive(Debug)]
    pub struct User {
        name: String,
        age: i32
    }
    
    impl User {
        pub fn new_user(name: String, age: i32) -> User {
            User{
                name,
                age
            }
        }
        pub fn name(&self) -> &str {
            &self.name
        }
    }
    
    pub fn add(x: i32, y: i32) -> i32 {
        x + y 
    }
    

    user_info.rs里导出

    pub mod user;
    

    main.rs调用

    mod user_info;
    use user_info::user::User;
    
    fn main() {
        let u1 = User::new_user(String::from("tom"), 5);
        println!("user name: {}", u1.name());
        println!("1+2: {}", user_info::user::add(1, 2));
    }
    
    

    使用外部包

    使用外部包,一般就是从crates.io下载,当然也可以自己指写下载地点,或者使用我们本地的库,或者自建的的仓库。

    一般方式

    Cargo.tomldependencies下写要导入的依赖库

    [dependencies]
    regex = "0.1.41"
    

    运行cargo build会从crates.io下载依赖库。
    使用的时候,直接使用use引入

    use regex::Regex;
    
    fn main() {
        let re = Regex::new(r"^d{4}-d{2}-d{2}$").unwrap();
        println!("Did our date match? {}", re.is_match("2014-01-01"));
    }
    

    指定库地址

    除了crates.io下载依赖库,也可以自己指定地址,也可以指定branch tag commit,比如下面这个

    [dependencies]
    # 可以和包不同名,也可以同名
    my_rust_lib_1={package="my_lib_1",git="ssh://git@github.com/lpxxn/my_rust_lib_1.git",tag="v0.0.2"}
    

    就是从github.com/lpxxn/my_rust_lib_1上下载包。也可以使用https

    my_rust_lib_1={package="my_lib_1",git="https://github.com/lpxxn/my_rust_lib_1.git",branch="master"}
    

    执行cargo build就会自动下载,使用的时候也是一样的。

    use my_rust_lib_1;
    fn main() {
        println!("Hello, world!");
        println!("{}", my_rust_lib_1::add(1, 2));
        let u = my_rust_lib_1::User::new_user(String::from("tom"), 2);
        println!("user: {:#?}", u);
    }
    
    

    使用本地的库

    我们新建一个二进制库项目

    cargo new pkg_demo_3
    

    然后在pkg_demo_3内建一个库项目

    cargo new --lib utils
    

    然后就可以在 utils里写我们的库代码了
    看一下现在的目录结构

    utils库的user.rs里还是我们上面的代码

    #[derive(Debug)]
    pub struct User {
        name: String,
        age: i32
    }
    
    impl User {
        pub fn new_user(name: String, age: i32) -> User {
            User{
                name,
                age
            }
        }
        pub fn name(&self) -> &str {
            &self.name
        }
    }
    
    pub fn add(x: i32, y: i32) -> i32 {
        x + y 
    }
    

    lib.rs里对user模块导出

    pub mod user;
    pub use user::User;
    

    然后在我们的二进制库的Cargo.toml引入库

    [dependencies]
    utils = { path = "utils", version = "0.1.0" }
    

    path就是库项目的路径
    main.rs使用use引入就可以使用了

    use utils::User;
    
    fn main() {
        let u = User::new_user(String::from("tom"), 5);
        println!("user: {:#?}", u);
    }
    

    自建私有库

    除了crates.io也可以自建registrie。这个有时间再重新写一篇帖子单独说,可以先看一下官方文档。
    官方文档:registrie
    依赖官方文档
    帖子 github 代码地址

  • 相关阅读:
    TTTTTTTTTTTTTTTTTTT UVA 2045 Richness of words
    hdu 5723 Abandoned country 最小生成树+子节点统计
    hdu 5792 World is Exploding 树状数组+离散化+容斥
    MySQL字符集详解
    MySQL的sql语言分类DML、DQL、DDL、DCL、
    MySQL5.6的4个自带库详解
    Win10下安装MySQL5.6
    {MySQL数据库初识}一 数据库概述 二 MySQL介绍 三 MySQL的下载安装、简单应用及目录介绍 四 root用户密码设置及忘记密码的解决方案 五 修改字符集编码 六 初识sql语句
    {python--GIL锁}一 介绍 二 GIL介绍 三 GIL与Lock 四 GIL与多线程 五 多线程性能测试
    Navicat安装及简单使用
  • 原文地址:https://www.cnblogs.com/li-peng/p/13587910.html
Copyright © 2011-2022 走看看