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

แยก Module ไปคนละไฟล์

ที่ผ่านมา ตัวอย่างทั้งหมดในบทนี้ประกาศ module หลายตัวในไฟล์เดียว เมื่อ module ใหญ่ คุณอาจอยากย้าย definition ของพวกมันไปไฟล์แยก เพื่อทำให้โค้ด ง่ายต่อการ navigate

เช่น เริ่มจากโค้ดใน Listing 7-17 ที่มี module ร้านอาหารหลายตัว เราจะดึง module เข้าไฟล์ แทนการมี module ทั้งหมดประกาศในไฟล์ crate root ในกรณีนี้ ไฟล์ crate root คือ src/lib.rs แต่ขั้นตอนนี้ก็ใช้ได้กับ binary crate ที่ ไฟล์ crate root คือ src/main.rs

ก่อนอื่น เราจะดึง module front_of_house ออกไปไฟล์ของมันเอง ลบโค้ดภายใน curly bracket สำหรับ module front_of_house เหลือแค่การประกาศ mod front_of_house; เพื่อให้ src/lib.rs มีโค้ดที่แสดงใน Listing 7-21 หมายเหตุว่านี่จะ compile ไม่ผ่านจนกว่าเราจะสร้างไฟล์ src/front_of_house.rs ใน Listing 7-22

Filename: src/lib.rs
mod front_of_house;

pub use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
}
Listing 7-21: ประกาศ module front_of_house ที่ body จะอยู่ใน src/front_of_house.rs

ถัดไป วางโค้ดที่อยู่ใน curly bracket เข้าไฟล์ใหม่ชื่อ src/front_of_house.rs ดังที่แสดงใน Listing 7-22 Compiler รู้ว่าจะมอง ในไฟล์นี้ เพราะมันเจอการประกาศ module ใน crate root ที่ชื่อ front_of_house

Filename: src/front_of_house.rs
pub mod hosting {
    pub fn add_to_waitlist() {}
}
Listing 7-22: definition ภายใน module front_of_house ใน src/front_of_house.rs

หมายเหตุว่าคุณต้อง load ไฟล์โดยใช้การประกาศ mod ครั้งเดียว ใน module tree ของคุณ เมื่อ compiler รู้ว่าไฟล์เป็นส่วนของโปรเจกต์ (และรู้ว่าโค้ด อยู่ที่ไหนใน module tree เพราะคุณวาง statement mod ที่ไหน) ไฟล์อื่นใน โปรเจกต์ของคุณควรอ้างถึงโค้ดของไฟล์ที่ load โดยใช้ path ไปยังตำแหน่งที่มัน ถูกประกาศ ดังที่ครอบคลุมในส่วน “Path สำหรับอ้างถึง Item ใน Module Tree” พูดอีก อย่าง mod ไม่ใช่ operation “include” ที่คุณอาจเคยเห็นในภาษาโปรแกรม อื่น

ถัดไป เราจะดึง module hosting ออกไปไฟล์ของมันเอง กระบวนการต่างกันนิด หน่อย เพราะ hosting เป็น module ลูกของ front_of_house ไม่ใช่ของ module root เราจะวางไฟล์สำหรับ hosting ใน directory ใหม่ที่จะตั้งชื่อ ตามบรรพบุรุษใน module tree ในกรณีนี้ src/front_of_house

ในการเริ่มย้าย hosting เราเปลี่ยน src/front_of_house.rs ให้มีแค่การ ประกาศของ module hosting:

Filename: src/front_of_house.rs
pub mod hosting;

จากนั้น เราสร้าง directory src/front_of_house และไฟล์ hosting.rs เพื่อมี definition ที่ทำใน module hosting:

Filename: src/front_of_house/hosting.rs
pub fn add_to_waitlist() {}

ถ้าแทนเราใส่ hosting.rs ใน directory src compiler จะคาดว่าโค้ด hosting.rs อยู่ใน module hosting ที่ประกาศใน crate root และไม่ ประกาศเป็นลูกของ module front_of_house กฎของ compiler สำหรับไฟล์ไหนที่ จะเช็คสำหรับโค้ดของ module ไหน หมายความว่า directory และไฟล์ match กับ module tree ใกล้กว่า

Path ไฟล์ทางเลือก

ที่ผ่านมาเราครอบคลุม path ไฟล์ที่ idiomatic ที่สุดที่ Rust compiler ใช้ แต่ Rust รองรับสไตล์ path ไฟล์เก่ากว่าด้วย สำหรับ module ชื่อ front_of_house ที่ประกาศใน crate root compiler จะมองหาโค้ดของ module ใน:

  • src/front_of_house.rs (สิ่งที่เราครอบคลุม)
  • src/front_of_house/mod.rs (สไตล์เก่ากว่า ยังรองรับ path)

สำหรับ module ชื่อ hosting ที่เป็น submodule ของ front_of_house compiler จะมองหาโค้ดของ module ใน:

  • src/front_of_house/hosting.rs (สิ่งที่เราครอบคลุม)
  • src/front_of_house/hosting/mod.rs (สไตล์เก่ากว่า ยังรองรับ path)

ถ้าคุณใช้ทั้งสองสไตล์สำหรับ module เดียวกัน คุณจะได้ compiler error การใช้สไตล์ผสมกันสำหรับ module ต่างกันในโปรเจกต์เดียวกันอนุญาต แต่อาจ ทำให้คนที่ navigate โปรเจกต์ของคุณสับสน

ข้อเสียหลักของสไตล์ที่ใช้ไฟล์ชื่อ mod.rs คือโปรเจกต์ของคุณอาจจบลงด้วย ไฟล์ชื่อ mod.rs หลายตัว ซึ่งอาจสับสนเมื่อคุณเปิดพวกมันใน editor พร้อม กัน

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

หมายเหตุว่า statement pub use crate::front_of_house::hosting ใน src/lib.rs ก็ไม่ได้เปลี่ยน และ use ไม่มีผลต่อไฟล์ไหนที่ถูก compile เป็นส่วนของ crate Keyword mod ประกาศ module และ Rust มองในไฟล์ที่ชื่อ เดียวกับ module สำหรับโค้ดที่ไปใน module นั้น

สรุป

Rust ให้คุณแบ่ง package เป็นหลาย crate และ crate เป็นหลาย module เพื่อ ให้คุณอ้างถึง item ที่ประกาศใน module หนึ่งจากอีก module ได้ คุณทำได้โดย ระบุ absolute หรือ relative path Path เหล่านี้นำเข้า scope ด้วย statement use ได้ เพื่อให้คุณใช้ path สั้นกว่าสำหรับการใช้ item หลายครั้งใน scope นั้น โค้ด module เป็น private โดย default แต่คุณทำให้ definition เป็น public ได้ โดยเพิ่ม keyword pub

ในบทถัดไป เราจะดูโครงสร้างข้อมูล collection ใน standard library ที่คุณใช้ ในโค้ดที่จัดระเบียบดีของคุณได้