สรุป The Rust Programming Language ฉบับมือเก่า ตอนที่ 7
บทความนี้สรุปจากหนังสือ The Rust Programming Language chapter 7 ด้วยความคิดเห็นของผมเอง อาจมีการตีความที่มีโอกาสผิดพลาดได้ ทางที่ดีถ้าอยากได้ reference จริงๆแนะนำต้นทางครับ
บทนี้จะเกี่ยวกับการจัดระเบียบ project structure ของ Rust โดยจะเรียกรวมๆว่า module system
ประกอบไปด้วย Packages, Crates, Modules และ Paths
Packages and Crates
Crates เป็นหน่วยย่อยที่สุดที่ Rust compiler จะ build ในแต่ละครั้ง แบ่งเป็น 2 แบบคือ
- Binary crate — มองว่าเป็น executable ที่ต้องมี fn main() เป็น entrypoint
- Library crate — เอิ่ม… ก็คือ library 😅เอาไว้แชร์ให้ project อื่นๆใช้
Package คือ project เรานี่แหล่ะที่ต้องมีอย่างน้อย 1 crate และจะมีกี่ binary crates ก็ได้แต่จะมีได้อย่างมากสุดคือ 1 library crate
Crate root ของ library by default คือ src/lib.rs
ส่วนของ binary คือ src/main.rs
Binary crates อื่นๆที่ไม่ใช่ root
จะอยู่ใน src/bin/
Modules and Paths
สำหรับ modules ก็จะเป็นหน่วยย่อยที่อยู่ใน crate อีกที พูดง่ายๆก็คือใน 1 crates เราสามารถ define ได้หลาย modules
ยกตัวอย่างเช่น Restuarant crate อาจจะมี module kitchen, module cashier หรือ module tables อะไรแบบนี้
การสร้าง module ก็จะทำได้โดยการสร้าง mod [module_name];
แบบนี้ เสร็จแล้วตอน compile ตัว compiler ก็จะไปหา code ของ module ตามนี้
- Inline -> อันนี้คือประกาศตรงที่ประกาศ module เลย
mod Kitchen {
// ...body
}
- In the file `src/[module_name].rs`
- In the file `src/[module_name]/mod.rs`
และ module สามารถประกาศ module ซ้อน module ได้และเรียกว่า submodule
โดย folders ของ submodules ก็จะอยู่ภายใน folder ของ parent module ไป (ตรงนี้แนะนำว่าดู original content อาจจะเข้าใจง่ายกว่า)
module เป็น private by default (หมายความว่าเฉพาะสิ่งที่อยู่ภายใน module นั้นเท่านั้นที่จะสามารถ refer ถึงของใน module นั้นได้ รวมถึง submodules)
เราสามารถประกาศ public module ได้แบบนี้ pub mod [module_name]
ก็จะทำให้ external code เรียกใช้ของใน module ได้
ต่อมาทางหนังสือก็จะพูดถึงการ refer ไปที่ path ของพวก module แล้วก็ของใน module ซึ่ง… เอาจริงๆก็ไม่ได้มีอะไรเท่าไหร่ คล้ายเวลาเรา refer พวก filesystem path เลย
ด้วยความที่คล้าย filesystem path เลยทำให้ใช้ได้ทั้งแบบ absolute และ relative
เช่น code ด้านล่างนี้เป็นต้น
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
}
ที่เหลือก็เป็นเรื่องของ privacy แล้วว่าเข้าถึงได้ไหม และด้วยความที่ผมขี้เกียจ และบทความนี้มีไว้สำหรับมือเก่า ก็ไป skimming เอาละกันเนอะ ตรงนี้ไม่ได้มีอะไรน่าสงสัยเท่าไหร่
มีเรื่องที่เกี่ยวกับ path
ก็คือการที่เราสามารถ bringing paths into scope ได้ พูดง่ายๆก็คือเทียบกับภาษาอื่นเป็นการ include, using, require
อะไรทำนองนี้นั่นแหล่ะ แต่ Rust จะได้ keyword ว่า use
มีความน่าสนใจเล็กน้อยตรง
- สามารถ re-export ได้แบบนี้
pub use create::front_of_house::housing;
- สามารถใช้ nested paths ได้แบบนี้
use std::io::{self, Write};
- สามารถใช้ glob operator ได้แบบนี้
use std::collections::*;
ต่อมาก็จะเป็นเรื่องของการที่เราสามารถ split module ไปอยู่ใน file ของตัวเองได้ ซึ่งจริงๆก็เหมือนกับที่ mentioned ไว้ด้านบน พูดก็คือสมมติเราประกาศ module แบบนี้ใน crate scope
mod front_of_house;
ทีนี้ตัว implementation ของ module เราก็จะสามารถทำได้ 3 ที่ตามด้านบน (inline, src/[module_name].rs, src/[module_name]/mod.rs
) แต่ตัวสุดท้ายเค้าบอกว่าเป็น old style เพราะงั้นก็น่าจะ prefer แบบที่ 1 กับ 2 มากกว่ามั้ง
จบแล้วครับบทที่ 7