Rust 学习指南 - Rust 代码组织

2,765 阅读4分钟
原文链接: www.codemore.top


rust的代码组织可以分为函数,模块,crate,workspace。workspace管理不同的crate,crate管理不同的mod,mod管理不同的函数。

函数

函数是组织代码最小的单位例如:

fn main() {
  greet(); //do one thing
  ask_location(); //do another thing
}
fn greet() {
  println!("Hello!");
}
fn ask_location() {
  println!("Where are you from?");
}

在同一个文件中为函数添加单元测试

#[test] 
fn test_greet() {
    assert_eq!("Hello, world!", greet())
}

#[test] 属性表示这个函数是一个单元测试。

mod
mod 和代码放在同一个文件
fn main(){
	greetings::hello();
}
mod greetings {
	pub fn hello() {
		println!("Hello world !");
	}
}

嵌套mod

fn main(){
	phrases::greetints::hello();
}
mod phrases {
	pub mod greetings {
		pub fn hello(){
			println!("Hello, world!");
		}
	}
}

对于私有函数可以在同一mod或者子mod中调用

fn main() {
  phrases::greet();
}
mod phrases {
  pub fn greet() {
    hello(); //or self::hello();
  }
  fn hello() {
    println!("Hello, world!");
  }
}
fn main() {
  phrases::greetings::hello();
}
mod phrases {
  fn private_fn() {
    println!("Hello, world!");
  }
  pub mod greetings {
    pub fn hello() {
      super::private_fn();
    }
  }
}

在上面的程序中,self表示当前的mod,super表示父mod。

将mod分散到同一个路径下的不同文件中
//  main.rs
mod greetings; // import greetings module
fn main() {
  greetings::hello();
}
// greetings.rs
// 不需要显示声明mod,默认即是文件名作为mod名
pub fn hello() { 
  println!("Hello, world!");
}

如果mod文件中使用mod关键字包装:

// ↳ main.rs
mod phrases;
fn main() {
  phrases::greetings::hello();
}
// ↳ phrases.rs
pub mod greetings { 
  pub fn hello() {
    println!("Hello, world!");
  }
}
mod 分散到不同路径的不同文件

mod.rs 是真个路径下的mod的入口文件,所有在同一路径下的文件都是它的子mod。

// ↳ main.rs
mod greetings;
fn main() {
  greetings::hello();
}
// ↳ greetings/mod.rs
pub fn hello() { 
  println!("Hello, world!");
}

放到不同的文件下

// ↳ main.rs
mod phrases;
fn main() {
    phrases::greetings::hello();
}
// ↳ phrases/mod.rs
pub mod greetings;  // 在mod.rs 使用pub mod xxx 声明需要到出的mod
// ↳ phrases/greetings.rs
pub fn hello() {
  println!("Hello, world!");
}
crate
lib.rs 和可执行文件在同一个crate中

当编写可执行文件的时候,可以将其他函数放到src/lib.rs 中,在src/main.rs 中引用使用

cargo new --bin greetings

touch greetings/src/lib.rs
// 01. greetings/src/lib.rs
pub fn hello() {
    println!("Hello, world!");
}
// 02. greetings/src/main.rs
extern crate greetings;
fn main() {
    greetings::hello();
}

lib.rs 文件中引用其他的文件

cargo new --bin phrases

touch phrases/src/lib.rs

touch phrases/src/greetings.rs

// # Think we modify following files
// 01. phrases/src/greetings.rs
pub fn hello() {
    println!("Hello, world!");
}
// 02. phrases/src/main.rs
extern crate phrases;
fn main() {
    phrases::greetings::hello();
}
// 03. phrases/src/lib.rs
pub mod greetings; 
在Cargo.toml 中声明依赖

基于文件路径的依赖:

[package]
name = "phrases"
version = "0.1.0"
authors = ["Dumindu Rajarathna"]
[dependencies]
greetings = { path = "greetings" }
// 02. phrases/greetings/src/lib.rs
pub fn hello() {
    println!("Hello, world!");
}
// 03. phrases/src/main.rs
extern crate greetings;
fn main() {
    greetings::hello();
}

基于git的依赖:

// -- Cargo.toml --
[dependencies] 
rocket = { git = "https://github.com/SergioBenitez/Rocket" }
rocket = { git = "https://github.com/SergioBenitez/Rocket", branch = "v0.3" } 
rocket = { git = "https://github.com/SergioBenitez/Rocket", tag = "v0.3.2" } 
rocket = { git = "https://github.com/SergioBenitez/Rocket", rev = "8183f636305cef4adaa9525506c33cbea72d1745" }

基于crates.io 版本

[dependencies]
test_crate_hello_world = "0.1.0"
workspace

当代码量越来越大的时候,一个项目可能包含了多个crate,rust通过workspace来支持这种情况。

// # Think we run
mkdir greetings
touch greetings/Cargo.toml
cargo new greetings/lib
cargo new --bin greetings/examples/hello
// # That generates,
.
├── Cargo.toml
├── examples
│  └── hello
│     ├── Cargo.toml
│     └── src
│        └── main.rs
└── lib
   ├── Cargo.toml
   └── src
      └── lib.rs
// # Think we modify following files
// 01. greetings/Cargo.toml
[workspace]
members = [
    "lib",
    "examples/hello"
]
// 02.1 greetings/lib/Cargo.toml
[package]
name = "greetings"
version = "0.1.0"
authors = ["Dumindu Madunuwan"]
[dependencies]
// 02.2 greetings/lib/src/lib.rs
pub fn hello() {
    println!("Hello, world!");
}
// 03.1 greetings/examples/hello/Cargo.toml
[package]
name = "hello"
version = "0.1.0"
authors = ["Dumindu Madunuwan"]
[dependencies]
greetings = { path = "../../lib" }
// 03.2 greetings/examples/hello/src/main.rs
extern crate greetings;
fn main() {
    greetings::hello();
}
use

use 的主要作用就是简化,无需每次调用都写全路径,例如:

mod phrases { 
  pub mod greetings { 
    pub fn hello() { 
      println!("Hello, world!");
    }
  }
}
fn main() { 
  phrases::greetings::hello(); // using full path
}

使用use

use phrases::greetings;
fn main() { 
  greetings::hello();
}
// 02. create alias for module elements
use phrases::greetings::hello;
fn main() { 
  hello();
}
// 03. customize names with as keyword
use phrases::greetings::hello as greet;
fn main() { 
  greet();
}

use 的另一个作用就是将元素倒入到当前作用域

fn hello() -> String {
  "Hello, world!".to_string()
}
#[cfg(test)]
mod tests {
  use super::hello; //import hello() into scope
  #[test]
  fn test_hello() {
    assert_eq!("Hello, world!", hello()); //if not using above use statement, we can run same via super::hello()
  }
}

use 导入标准库

use std::fs::File;
fn main() {
    File::create("empty.txt").expect("Can not create the file!");
}
// -- 02. importing module and elements--
std::fs::{self, File} //use std::fs; use std::fs::File
fn main() {
    fs::create_dir("some_dir").expect("Can not create the directry!");
    File::create("some_dir/empty.txt").expect("Can not create the file!");
}
// -- 03. importing multiple elements
use std::fs::File;
use std::io::{BufReader, BufRead}; //use std::io::BufReader; use std::io::BufRead;
fn main() {
    let file = File::open("src/hello.txt").expect("file not found");
    let buf_reader = BufReader::new(file);
    for line in buf_reader.lines() {
        println!("{}", line.unwrap());
    }
}

pub use 将某个mod中的某个成员导入

mod phrases;
fn main() {
    phrases::hello(); //not directly map
}
// ↳ phrases/mod.rs
pub mod greetings;
pub use self::greetings::hello; //re-export greetings::hello to phrases
// ↳ phrases/greetings.rs
pub fn hello() {
  println!("Hello, world!");
}

rust 默认导入的标准库

// Reexported core operators
pub use marker::{Copy, Send, Sized, Sync};
pub use ops::{Drop, Fn, FnMut, FnOnce};
// Reexported functions
pub use mem::drop;
// Reexported types and traits
pub use boxed::Box;
pub use borrow::ToOwned;
pub use clone::Clone;
pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
pub use convert::{AsRef, AsMut, Into, From};
pub use default::Default;
pub use iter::{Iterator, Extend, IntoIterator};
pub use iter::{DoubleEndedIterator, ExactSizeIterator};
pub use option::Option::{self, Some, None};
pub use result::Result::{self, Ok, Err};
pub use slice::SliceConcatExt;
pub use string::{String, ToString};
pub use vec::Vec;