Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

ควบคุม Scope และ Privacy ด้วย Module

ในส่วนนี้ เราจะพูดถึง module และส่วนอื่นของระบบ module ได้แก่ path ที่ ให้คุณตั้งชื่อ item, keyword use ที่นำ path เข้า scope และ keyword pub เพื่อทำให้ item เป็น public เราจะพูดถึง keyword as, package ภายนอก และ glob operator ด้วย

Cheat Sheet ของ Module

ก่อนเราเข้าสู่รายละเอียดของ module และ path ที่นี่เราให้ reference ด่วน เกี่ยวกับวิธีที่ module, path, keyword use และ keyword pub ทำงานใน compiler และวิธีที่นักพัฒนาส่วนใหญ่จัดระเบียบโค้ดของพวกเขา เราจะผ่าน ตัวอย่างของกฎเหล่านี้แต่ละข้อตลอดบทนี้ แต่นี่เป็นที่ดีที่จะอ้างถึงเพื่อ เตือนความจำว่า module ทำงานยังไง

  • เริ่มจาก crate root: เมื่อ compile crate compiler มองในไฟล์ crate root ก่อน (โดยปกติ src/lib.rs สำหรับ library crate และ src/main.rs สำหรับ binary crate) สำหรับโค้ดที่จะ compile
  • ประกาศ module: ในไฟล์ crate root คุณประกาศ module ใหม่ได้ สมมติคุณ ประกาศ module “garden” ด้วย mod garden; Compiler จะมองหาโค้ดของ module ในที่เหล่านี้:
    • Inline ภายใน curly bracket ที่แทน semicolon ตาม mod garden
    • ในไฟล์ src/garden.rs
    • ในไฟล์ src/garden/mod.rs
  • ประกาศ submodule: ในไฟล์ใด ๆ นอกจาก crate root คุณประกาศ submodule ได้ เช่น คุณอาจประกาศ mod vegetables; ใน src/garden.rs Compiler จะมองหาโค้ดของ submodule ภายใน directory ที่ตั้งชื่อตาม module พ่อ ใน ที่เหล่านี้:
    • Inline ตามด้วย mod vegetables ตรง ๆ ภายใน curly bracket แทน semicolon
    • ในไฟล์ src/garden/vegetables.rs
    • ในไฟล์ src/garden/vegetables/mod.rs
  • Path ไปยังโค้ดใน module: เมื่อ module เป็นส่วนหนึ่งของ crate ของคุณ คุณอ้างถึงโค้ดใน module นั้นจากที่อื่นใดใน crate เดียวกันได้ ตราบที่กฎ privacy อนุญาต โดยใช้ path ไปยังโค้ด เช่น type Asparagus ใน module garden vegetables จะถูกหาที่ crate::garden::vegetables::Asparagus
  • Private vs. public: โค้ดภายใน module เป็น private จาก module พ่อ โดย default ในการทำให้ module เป็น public ประกาศด้วย pub mod แทน mod ในการทำให้ item ภายใน module public เป็น public ด้วย ใช้ pub ก่อนการประกาศ
  • Keyword use: ภายใน scope keyword use สร้าง shortcut ของ item เพื่อลดการเขียน path ยาว ๆ ซ้ำ ใน scope ใดก็ตามที่อ้างถึง crate::garden::vegetables::Asparagus ได้ คุณสร้าง shortcut ด้วย use crate::garden::vegetables::Asparagus; ได้ และจากนั้นคุณเขียนแค่ Asparagus เพื่อใช้ type นั้นใน scope ก็พอ

ที่นี่ เราสร้าง binary crate ชื่อ backyard ที่แสดงกฎเหล่านี้ Directory ของ crate ก็ชื่อ backyard มีไฟล์และ directory เหล่านี้:

backyard
├── Cargo.lock
├── Cargo.toml
└── src
    ├── garden
    │   └── vegetables.rs
    ├── garden.rs
    └── main.rs

ไฟล์ crate root ในกรณีนี้คือ src/main.rs และมี:

Filename: src/main.rs
use crate::garden::vegetables::Asparagus;

pub mod garden;

fn main() {
    let plant = Asparagus {};
    println!("I'm growing {plant:?}!");
}

บรรทัด pub mod garden; บอก compiler ให้ include โค้ดที่มันเจอใน src/garden.rs ซึ่งคือ:

Filename: src/garden.rs
pub mod vegetables;

ที่นี่ pub mod vegetables; หมายความว่าโค้ดใน src/garden/vegetables.rs ถูก include ด้วย โค้ดนั้นคือ:

#[derive(Debug)]
pub struct Asparagus {}

ทีนี้มาเข้าสู่รายละเอียดของกฎเหล่านี้และแสดงพวกมันในการใช้งาน!

จัดกลุ่มโค้ดที่ผูกกันใน Module

Module ให้เราจัดระเบียบโค้ดภายใน crate สำหรับความอ่านง่ายและการใช้ซ้ำ ได้ง่าย Module ยังให้เราควบคุม privacy ของ item ด้วย เพราะโค้ดภายใน module เป็น private โดย default Private item เป็นรายละเอียด implementation ภายในที่ไม่มีให้ภายนอกใช้ เราเลือกทำให้ module และ item ภายในเป็น public ได้ ซึ่งเปิดเผยพวกมันให้โค้ดภายนอกใช้และพึ่งพา

เป็นตัวอย่าง มาเขียน library crate ที่ให้ functionality ของร้านอาหาร เรา จะประกาศ signature ของฟังก์ชัน แต่ทิ้ง body ว่างไว้ เพื่อโฟกัสที่การจัด ระเบียบของโค้ดมากกว่าการ implement ร้านอาหาร

ในอุตสาหกรรมร้านอาหาร บางส่วนของร้านอาหารถูกอ้างถึงเป็น front of house และอื่น ๆ เป็น back of house Front of house คือที่ที่ลูกค้าอยู่ ซึ่งรวม ที่ที่ host จัดที่นั่งลูกค้า, server รับ order และเงิน, และ bartender ทำ เครื่องดื่ม Back of house คือที่ที่ chef และพ่อครัวทำงานในครัว, คนล้าง จานทำความสะอาด และผู้จัดการทำงาน administrative

ในการ structure crate ของเราในแบบนี้ เราจัดระเบียบฟังก์ชันของมันเป็น module ซ้อน สร้าง library ใหม่ชื่อ restaurant โดยรัน cargo new restaurant --lib จากนั้นป้อนโค้ดใน Listing 7-1 เข้า src/lib.rs เพื่อประกาศ module และ signature ฟังก์ชัน — โค้ดนี้คือส่วน front of house

Filename: src/lib.rs
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() {}
    }
}
Listing 7-1: module front_of_house ที่มี module อื่นที่จากนั้นมีฟังก์ชัน

เราประกาศ module ด้วย keyword mod ตามด้วยชื่อของ module (ในกรณีนี้ front_of_house) body ของ module จากนั้นไปภายใน curly bracket ภายใน module เราวาง module อื่นได้ เหมือนในกรณีนี้กับ module hosting และ serving Module ยังเก็บ definition สำหรับ item อื่นได้ เช่น struct, enum, constant, trait และเหมือนใน Listing 7-1 ฟังก์ชัน

ด้วยการใช้ module เราจัดกลุ่ม definition ที่ผูกกันเข้าด้วยกัน และตั้งชื่อ ว่าทำไมพวกมันผูกกัน โปรแกรมเมอร์ที่ใช้โค้ดนี้นำทางโค้ดตามกลุ่ม แทนต้อง อ่านผ่าน definition ทั้งหมด ทำให้ง่ายขึ้นที่จะหา definition ที่เกี่ยวข้อง กับพวกเขา โปรแกรมเมอร์ที่เพิ่ม functionality ใหม่ให้โค้ดนี้รู้ว่าจะวาง โค้ดที่ไหน เพื่อให้โปรแกรมจัดระเบียบ

ก่อนหน้านี้ เราเอ่ยว่า src/main.rs และ src/lib.rs เรียกว่า crate root เหตุผลของชื่อพวกมันคือเนื้อหาของหนึ่งในสองไฟล์เหล่านี้ ประกอบ เป็น module ชื่อ crate ที่ root ของโครงสร้าง module ของ crate รู้จัก ในชื่อ module tree

Listing 7-2 แสดง module tree สำหรับโครงสร้างใน Listing 7-1

crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment
Listing 7-2: module tree สำหรับโค้ดใน Listing 7-1

tree นี้แสดงว่า module บางตัวซ้อนภายใน module อื่นอย่างไร เช่น hosting ซ้อนภายใน front_of_house tree ยังแสดงว่า module บางตัวเป็น sibling หมายความว่าพวกมันประกาศใน module เดียวกัน — hosting และ serving เป็น sibling ที่ประกาศภายใน front_of_house ถ้า module A ถูกบรรจุภายใน module B เราบอกว่า module A เป็น ลูก ของ module B และ module B เป็น พ่อ ของ module A สังเกตว่าทั้ง module tree มี root อยู่ภายใต้ module implicit ที่ ชื่อ crate

module tree อาจเตือนคุณถึง directory tree ของ filesystem บนคอมพิวเตอร์ ของคุณ — นี่เป็นการเปรียบเทียบที่เหมาะมาก! เหมือนกับ directory ใน filesystem คุณใช้ module จัดระเบียบโค้ดของคุณ และเหมือนกับไฟล์ใน directory เราต้องการวิธีหา module ของเรา