Rust 的代码组织
代码组织主要包括:
Crate的类型:
Crate Root:
一个 Package:
Cargo 的惯例
src/main.rs
:
src/lib.rs
:
Cargo 把 crate root 文件交给 rustc 来构建 library 或 binary
如果 package 下有一个lib.rs,就说明 package 下面有一个 library crate,这个 lib.rs 就是这个 library crate 的入口文件,crate 名字也是叫 my-project.
一个 Package 可以同时包含 src/main.r s和 src/lib.rs
一个 Package 可以有多个 binary crate:
Crate 的作用
将相关功能组合到一个作用域内,便于在项目间进行共享,防止冲突。例如 rand crate,访问它的功能需要通过它的名字:rand
定义 module 来控制作用域和私有性
Module:
建立 module:
可包含其它项(struct、enum、常量、trait、函数等)的定义
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
fn seat_at_table() {}
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
src/main.rs
和 src/lib.rs
叫做 crate roots
:
为了在 Rust 的模块中找到某个条目,需要使用路径。路径的两种形式:
::
私有边界(privacy boundary)
Pub 关键字
使用 pub
关键字将某些条目标记为公共的,同为根下的模块尽管都是私有,也可以访问
super 关键字
用来访问父级模块路径中的内容,类似文件系统中的 ..
,例子如下:
mod back_of_house {
fn fix_incorrect_order() {
cook_order();
super::serve_order();
crate::serve_order();
}
fn cook_order() {}
}
fn serve_order() {}
pub struct
pub 放在 struct 前:
struct 的字段需要单独设置 pub 来变成公有
mod back_of_house {
pub struct Breakfast {
pub toast: String,
fruit: String,
}
impl Breakfast {
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
fruit: String::from("strawberry"),
}
}
}
}
pub fn eat_at_restaurant() {
let mut meal = back_of_house::Breakfast::summer("Rye");
println!("I'd like {} toast please.", meal.toast);
}
pub enum
pub 放在 enum 前:
enum 的变体也都是公共的
mod back_of_house {
pub enum Appetizer {
Soup,
Salad
}
}
可以使用 use
将路径导入到作用域内,同样遵循私有性原则,即只有公共的才能被使用
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
fn some_function() {}
}
}
use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::some_function(); //报错,因为some_function为私有
}
使用 use
指定相对路径:use front_of_house::hosting;
可以直接将模块中的函数导入到作用域内,但是这样便无法区分该函数是在模块中定义还是在该文件内定义,因此通常的做法都是只导入到该函数的父模块,通过父模块调用函数。
对于函数和同名条目是这样,但是对于结构体和枚举,通常是指定完整路径,这是 use
的习惯用法。
use std::fmt;
use std::io;
fn f1() -> fmt::Result {}
fn f2() -> io::Result {}
as 关键字
as
关键字可以为引入的路径指定一个本地的别名,例子如下:
use std::fmt::Result;
use std::io::IOResult;
fn f1() -> Result {}
fn f2() -> IOResult {}
使用 pub use 重新导出名称
使用 use 将路径(名称)导入到作用域内后,该名称在此作用域内是私有的
pub use:重导出
pub use crate::front_of_house::hosting;
使用外部包
标准库(std)也被当做外部包,但是不需要修改 Cargo.toml 来包含 std,需要使用 use 将 std 中的特定条目引入当前作用域
use std::collections::HashMap;
使用嵌套路径清理大量 use 语句
如果使用同一个包或模块下的多个条目,可以使用嵌套路径在同一行内将上述路径进行引入
格式如下:路径相同的部分::{路径不同的部分}
,例子如下:
use std::cmp::Ordering;
use std::io;
//使用嵌套路径
use std::{cmp::Ordering, io};
//若是这样的引用
use std::io;
use std::io::Write;
//简写为
use std::io::{self, Write};
通配符*
使用 *
可以把路径中所有的公共条目都引入到作用域
use std::collections::*;
应用场景:
将模块内容移动到其它文件
模块定义时,如果模块名后边是 ;
,而不是代码块,Rust 会从与模块同名的文件中加载内容,同时项目文件夹结构要与模块层级结构一致。随着模块的变大,该技术可以把模块中的内容移动到其他文件中。
例如:文件 main.rs
:
pub mod back_of_house;
文件 back_of_house.rs
:
pub mod hosting;
这时必须在 src
下创建一个 back_of_house
的文件夹,里面创建一个 hosting.rs
文件,即为 src/back_of_house/hosting.rs
文件 hosting.rs
:
pub fn test() {}