
Learn Rust: Package, Crate and Module
Pacakge
เวลาเราใช้ Cargo จัดการ Rust project นั้น ตอนที่เรา cargo new project เราจะได้โครงสร้าง project ประมาณนี้
.
├── Cargo.toml
└── src
└── main.rs
ซึ่ง Cargo จะเรียกโครงสร้างแบบนี้ว่าเป็น 1 package
ทีนี้ใน 1 package Cargo จะแบ่งโค้ดเราออกเป็น crate เช่นจากที่สร้างมาให้ตามรูปเราจะมี root crate
คือ crate ที่ชื่อเดียวกันกับ package (project) นั่นแหละ ถ้าเราสร้าง package โดยคำสั่ง cargo new hello
ก็จะได้ root crate ชื่อ hello
Crate
ใน 1 crate ก็จะมีได้หลาย ๆ submodule ส่วนตัว root crate จะมองว่าเป็น root module ด้วยก็ได้ ซึ่ง submodule จะช่วยแบ่ง namespace ในการประกาศ function, namespace, type, var และ const ต่าง ๆ
ในโค้ดที่ cargo new สร้างให้เราจะเห็นแค่ src/main.rs
ซึ่งจะถูกเรียกว่า binary crate เพราะว่า
build แล้วได้ binary ที่เอามา execute ได้
นอกจากนั้นใน 1 package เรายังสามารถสร้าง library crate ที่จะถูกเรียกใช้ผ่าน binary crate หรือ publish ไปใช้
package อื่น ๆ ใช้ได้ด้วยโดยการเพิ่ม dependency ใน Cargo.toml
โดยโค้ด library crate จะถูกเก็บใน src/lib.rs
เช่น ใน lib.rs มีโค้ดแบบนี้
pub fn say_hello() {
println!("Hello, world!");
}
และใน main.rs มีโค้ดแบบนี้
fn main() {
hello::say_hello();
}
เราจะเห็นว่าเราใช้ hello::say_hello()
ใน main.rs ซึ่ง hello
คือชื่อ crate ที่เราสร้างขึ้นมา
และ say_hello
คือ function ที่อยู่ใน crate นั้น ๆ
เราต้องใส่ pub
ด้วยเพื่อให้สามารถเรียกใช้จาก crate อื่น ๆ ได้ ถ้าไม่ใส่เป็น private เรียกได้แต่ใน crate ตัวเอง
Module
เราสามารถสร้าง sub module เพิ่มใน crate ได้โดยใช้ keyword mod
เช่น
pub mod guest {
pub fn say_hello() {
println!("Hello, guest!");
}
}
ซึ่งเราต้องประกาศให้เป็น pub
ให้ mod
ด้วยเหมือนกันเพื่อให้สามารถเรียกใช้จาก crate อื่น ๆ ได้
โค้ดใน main ต้องการเรียกใช้ module นี้ ก็ใช้แบบนี้
fn main() {
hello::guest::say_hello();
}
นอกจากเราจะประกาศสิ่งต่าง ๆ ภายใต้ module ไว้ใน block {} ของ module แล้ว เรายังสามารถแยกโค้ด module ออกเป็นอีกไฟล์ได้
โดยสร้างไฟล์ชื่อเดียวกันกับ module เช่น src/guest.rs
และใส่โค้ดนี้ลงไป
pub fn say_hello() {
println!("Hello, guest!");
}
ส่วนใน root module src/lib.rs
ก็จะเหลือแค่ประกาศ module แบบนี้
pub mod guest;
นอกจากท่านี้แล้ว เรายังสามารถแยก module ออกเป็น folder ใหม่ได้เช่น src/guest/mod.rs
และใส่โค้ดนี้ลงไป
pub fn say_hello() {
println!("Hello, guest!");
}
เพื่อที่จะสามารถสร้าง sub module ของ guest ได้อีกชั้นนึงง่ายๆ เช่นเราอยากสร้าง module msg ใน guest ก็ทำได้โดย
- ประกาศ
pub mod msg;
ในsrc/guest/mod.rs
จะใส่โค้ดใน block ตรง ๆ ก็ได้ หรือ - สร้างไฟล์
src/guest/msg.rs
และใส่โค้ดลงไป หรือ - สร้าง folder
src/guest/msg
และสร้างsrc/guest/msg/mod.rs
และใส่โค้ดลงไป
Use module
เวลาเรียกใช้สิ่งที่อยู่ใน create อื่น ๆ หรือ sub module ของ crate อื่น ๆ ที่ประกาศเป็น public เราเห็นตัวอย่างไปแล้วว่าให้เริ่มจากชื่อ crate
แล้วใช้ ::
ค่อย ๆ เข้าถึงไปในแต่ละ sub module ตามลำดับ
แต่ถ้าเราไม่อยากเขียนยาว ๆ ทุกครั้งเราสามารถใช้ use
keyword มาช่วยได้ เช่น
use hello::guest::say_hello;
fn main() {
say_hello();
}
เราจะเห็นว่าเราใช้ use
กับ hello::guest::say_hello
แล้วเราสามารถเรียกใช้ say_hello()
ได้โดยตรง
หรือเราจะ use แค่ module ที่เราต้องการเฉย ๆ ก็ได้เช่น
use hello::guest;
fn main() {
guest::say_hello();
}
สรุป
- Package คือโครงสร้างของ Rust project ที่เราสร้างด้วย Cargo
- Crate คือโค้ดที่เราสร้างขึ้นมาเอง ซึ่งอาจจะเป็น binary crate หรือ library crate
- Module คือส่วนย่อย ๆ ของ crate ที่เราสร้างขึ้นมา ที่เราใช้เพื่อแบ่ง namespace ของ function, namespace, type, var และ const ต่าง ๆ
- เราสามารถใช้
use
keyword เพื่อเรียกใช้ module ที่เราต้องการโดยไม่ต้องเขียนชื่อ crate และ module ยาว ๆ ทุกครั้ง - เราสามารถแยก module ออกเป็นไฟล์หรือ folder ได้เพื่อให้โค้ดเราสะดวกขึ้น
- เราสามารถสร้าง sub module ของ module ได้โดยใช้
mod
keyword และสร้างไฟล์หรือ folder ใหม่ได้