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.rs
和src/lib.rs
,那么他就有两个crate
,如果想有多个二进制crate
,rust
约定需要将文件放在src/bin
目录下,每个文件就是一个单独的crate
。crate根
用来描述如何构建crate
的文件。比如src/main.rs
或者src/lib.rs
就是crate根
。crate根
文件将由Cargo
传递给rustc
来实际构建库或者二进制项目。- 带有
Cargo.toml
文件的包用来描述如何构建crate
,一个包可以最多有一个库crate
,任意多个二进制crate
。
模块
模块以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.toml
的dependencies
下写要导入的依赖库
[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 代码地址
rust 模块组织结构的更多相关文章
- 结合源码看nginx-1.4.0之nginx模块组织结构详解
目录 0. 摘要 1. nginx模块组织结构 2. nginx模块数据结构 3. nginx模块初始化 4. 一个简单的http模块 5. 小结 6. 参考资料 0. 摘要 nginx有五大优点:模 ...
- 【MM系列】SAP MM模块-组织结构介绍
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP MM模块-组织结构介绍 ...
- 【MM系列】SAP MM模块-组织结构第二篇
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP MM模块-组织结构第二篇 ...
- 【译】关于Rust模块的清晰解释
原文链接: http://www.sheshbabu.com/posts/rust-module-system/ 原文标题: Clear explanation of Rust's module sy ...
- 2-6 Opencv模块组织结构
https://opencv.org/releases.html https://sourceforge.net/projects/opencvlibrary/files/opencv-win/3.4 ...
- nginx 的模块及处理流程
nginx的内部结构是由核心部分和一系列的功能模块所组成.这样划分是为了使得每个模块的功能相对简单,便于开发,同时也便于对系统进行功能扩展.这样的模块化设计类似于面向对象中的接口类,它增强了 ...
- Rust 1.31正式发布,首次引入Rust 2018新功能
Rust 1.31是第一个实现了Rust 2018独有新功能并且不保证与现有代码库兼容的版本.Rust 2018相关工作正在进行中,而Rust 1.31只是整个三年开发周期的开始,这个开发周期将对这门 ...
- Duilib源码分析(一)整体框架
Duilib界面库是一款由杭州月牙儿网络技术有限公司开发的界面开源库,以viksoe项目下的UiLib库的基础上开发(此后也将对UiLib库进行源码分析):通过XML布局界面,将用户界面和处理逻辑彻底 ...
- 结合源码看nginx-1.4.0之nginx事件驱动机制详解
目录 0. 摘要 1. nginx事件模块组织结构 2. nginx事件模块数据结构及类图 3. nginx事件模块运行机制 4. 练习:一个简单的事件驱动模块 5. 小结 6. 参考源码
随机推荐
- luogu P5410 模板 扩展 KMP Z函数 模板
LINK:P5410 模板 扩展 KMP Z 函数 画了10min学习了一下. 不算很难 思想就是利用前面的最长匹配来更新后面的东西. 复杂度是线性的 如果不要求线性可能直接上SA更舒服一点? 不管了 ...
- 4.19 ABC F path pass i 容斥 树形dp
LINK:path pass i 原本想了一个点分治 yy了半天 发现重复的部分还是很难减掉 况且统计答案的时候有点ex. (点了别人的提交记录 发现dfs就过了 于是yy了一个容斥 发现可以直接减掉 ...
- CPU监控 线段树裸题
LINK:bzoj3064 此题甚好码了20min停下来思考的时候才发现不对的地方有点坑... 还真不好写来着 可这的确是线段树的裸题...我觉得我写应该没有什么大问题 不过思路非常的紊乱 如果是自己 ...
- java多线程的问题
1.多线程有什么用 (1) 发挥多核CPU的优势 单核CPU上所谓的"多线程"那是假的多线程,同一时间处理器只会处理一段逻辑,只不过线程之间切换得比较快,看着像多个线程" ...
- tracebace用法
介绍一下traceback 平时看到的程序的错误信息也就是traceback信息 举个简单例子: import traceback try: s = [1, 2, 3] print s[5] exce ...
- 当asp.net core偶遇docker二(打造个人docker镜像)
网络上的docker容器总有一些不尽人意的感觉,这个时候,就需要自己diy一个自用的. 比如我们想在163的mysql 5.7内diy一下,结果发现,这个不带vim,我想改造一个自用的mysql镜像, ...
- 【洛谷P3802】小魔女帕琪 题解(概率期望)
前言:蒟蒻太弱了,不会推式子QAQ -------------------- 题目链接 题目大意:给定$7$种能量晶体各$a_i$个,每次随机摸到一个晶体,如果连续摸到$7$个不同的晶体就会触发一次伤 ...
- Kaggle-pandas(3)
Summary-functions-and-maps 教程 在上一教程中,我们学习了如何从DataFrame或Series中选择相关数据. 正如我们在练习中所展示的,从我们的数据表示中提取正确的数据对 ...
- github开源文章生成pdf
最近需要研究ELK,然后在网上发现了有本书写的不错,然后搜到是在 github 上开源过的.这本书的时间有点久了,就想通过源码自己来生成一个 pdf 我使用的是 ubuntu 系统 step1:安装 ...
- 打开桌面的Eclipse闪退,打不开
参考了网上说的方法: .在C:/WINDOWS/system32 系统文件夹中ctrl+F 然后搜索java.exe,如果存在java.exe, javaw.exe etc.全部删除. 2.内存不足, ...