# 包和 Crate

一个包,包含一个或多个 crate,并且只有一个 Cargo.toml 文件,阐述如何构建这些 crate。

# 模块

// src/lib.rs
mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}
        fn seat_at_table() {}
    }
    
    mod serving {
        fn take_order() {}
        fn server_order() {}
        fn take_payment() {}
    }
}

相当于路径

crate
    front_of_house
        hosting
            add_to_waitlist
            seat_at_table
        serving
            take_order
            server_order
            take_payment

main.rslib.rs 都称为 crate 根

整个模块数都植根于隐式模块 crate 下

# 引用模块树的项

  1. 相对路径:以 self、super 来标识
  2. 绝对路径:以 crate 来标识

使用::分隔

mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}
    }
}
pub fn eat_at_restaurant () {
    // 绝对路径
    crate::front_of_house::hosting::add_to_waitlist();
    
    // 相对路径
    front_of_house::hosting::add_to_waitlist();
}

建议使用绝对路径,因为项目结构调整是经常的。

# 私有性边界

上面的代码编译会失败,因为知道路径,但有些是私有的,不给使用。

  • Rust 中所有的条目默认是私有的:函数、方法、struct、enum、模块、常量
  • 父级不能使用子级的东西,而子级可以使用父级的东西。

# pub - 使公有化

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist(){}
    }
}
pub fn eat_at_restaurant() {
    // 绝对路径
    crate::front_of_house::hosting::add_to_waitlist();
    
    // 相对路径
    front_of_house::hosting::add_to_waitlist();
}

内部的每一层都要加 pub 才能访问内部

同级是可以直接访问的

# super - 相对路径

super 可以改变模块访问边界,类似目录系统中的 ../ 上一层

fn server_order() {}
mod back_of_house {
    fn fix_incorrect_order() {
        cook_order();
        
        //super 改变路径位置
        // 注意:fn 不算是一层路径
        //mod 才是路径边界
        // 所以 super 是 back_of_house 的上一层
        super::server_order();
    }
    
    fn cook_order() {}
}

# pub struct

  • pub 放在 struct 前:
    • struct 是公共的
    • struct 内的字段默认是私有的
  • struct 字段前添加 pub 设置为公共的
mod back_of_house {
    pub struct Breakfast {
        pub toast: String,
        seasonal_fruit: String,
    }
    impl Breakfast {
        pub fn summer(toast: &str) -> Breakfast {
            Breakfast {
                toast: String::from(toast),
                seasonal_fruit: String::from("peaches"),
            }
        }
    }
}
pub fn eat_at_restuarant() {
    let mut meal = back_of_house::Breakfast::summer("Rye");
    //toast 字段是公共的,外部可以访问
    meal.toast = String::from("Wheat");
    println!("I'd like {} toast please", meal.toast);
    // 这里 seasonal_fruit 会报错,因为此字段是私有的,外部不可访问
    meal.seasonal_fruit = String::from("blueberries");
}

# pub enum

把 pub 放在 enum 前:

  • enum 是公共的
  • enum 的变体也都是公共的
mod back_of_house {
    pub enum Appetizer {
        // 以下变体,默认为公有的,此规则是例外;因为枚举在公共时才有意义
        Soup,
        Salad,
    }
}

# use - 关键词

使用 use 关键字将路径导入到作用域内

  • 可导入绝对路径或相对路径
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {};
    }
}
// 导入绝对路径,建议绝对路径
use crate::front_of_house::hosting;
// 以下一行是导入相对路径
// use front_of_house::hosting;
pub fn eat_at_restuarant() {
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
}

# use - 惯用用法

  1. 函数:将函数的父级模块引入作用域(指定到父级),目的:方便知道函数是外部还是当前文件定义的。
  2. struct、enum,其它:指定完整路径(指定到本身)
  3. 同名条目:指定到父级
use std::fmt;
use std::io;
// Result 同名,需要指定到父级
fn f1() -> fmt::Result {/*impl*/}
fn f2() -> io::Result {/*impl*/}

# as - 别名

as 关键字可以为 use 引入的路径指定本地的别名

use std::fmt::Result;
use std::io::Result as IoResult;
fn f1() -> Result {/*impl*/}
fn f2() -> IoResult {/*impl*/}

# pub use - 重新导出名称

在 use 前面添加 pub,重导出模块

// 外部不能访问
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {};
    }
}
// 重导出,这样外部能访问 hosting
pub use crate::front_of_house::hosting;
// 外部能访问
pub fn eat_at_restuarant() {
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
}

# package - 使用外部包

  1. Cargo.toml 添加依赖的包(package):国内建议配置镜像
    • https://crates.io
  2. use 将依赖包内特定的条目引入到作用域

# 嵌套路径 - 优化 use 语句

如果使用同一个包或模块下的多个条目,则导致多条 use 语句。可以提取公共部分,把不同的部分放到嵌套路径上。

  • 路径相同部分::{路径差异的部分}
// use std::cmp::Ordering;
// use std::io;
// 使用嵌套路径优化
use std::{cmp::Ordering, io};
fn main{}
  • 如果两个 use 路径之一是另外一个的子路径时:
// use std::io;
// use std::io::Write;
// 使用嵌套路径,以及 self 优化路径
use std::io::{self, Write};

# 通配符 *

  • 使用 * 可以把路径中所有的公共条目都引入到作用域。
  • 应用场景:
    • 测试。(将所有被测试代码引入到 tests 模块)
    • 用于预导入(prelude)模块

# 将模块拆分到其它文件

  • 模块定义时,如果模块名后面是 ; 结尾,而不是代码块时:

    • rust 会从与模块同名的文件中加载内容
    // 文件:src/lib.rs
    //rust 会找此文件目录下的 front_of_house.rs 文件
    mod front_of_house;
    // 文件:src/front_of_house.rs
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
  • 多层模块嵌套时:

// 文件:src/lib.rs
//rust 会找此文件目录下的 front_of_house.rs 文件
mod front_of_house;
// 文件:src/front_of_house.rs
//rust 会找此文件目录下的 front_of_house/hosting.rs 文件
pub mod hosting;
// src/front_of_house/hosting.rs
pub fn add_to_waitlist() {}
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Cecil 微信支付

微信支付

Cecil 支付宝

支付宝

Cecil PayPal

PayPal