前外交部副部长傅莹:一旦中美闹翻,有没有国家会站在中国一边

【少儿禁】马建《亮出你的舌苔或空空荡荡》

【成都mc是什么】成都mc浴室小黑屋见闻(史诗级巨瓜)

全球化丧钟,不仅为张一鸣而鸣

到底是谁杀害了在非洲的中国人

生成图片,分享到微信朋友圈

自由微信安卓APP发布,立即下载! | 提交文章网址
查看原文

Rust 模块应该如何组织结构?

李鹏 Rust编程指北 2022-09-19

关注「Rust编程指北」,一起学习 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 代码地址:https://github.com/lpxxn/rust_module

模块

模块以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:

https://doc.rust-lang.org/cargo/reference/registries.html#registries

依赖官方文档:

https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html

帖子 github 代码地址:

https://github.com/lpxxn/rust_module


作者:李鹏

出处:http://www.cnblogs.com/li-peng/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。




推荐阅读


觉得不错,点个赞吧

扫码关注「Rust编程指北


文章有问题?点此查看未经处理的缓存