แพ็กเกจ และ เครต (Packages and Crates)
ส่วนแรกสุดของระบบโมดูลที่เราจะมาทำความรู้จักกันคือ แพ็กเกจ (packages) และ เครต (crates)
เครต (crate) คือปริมาณโค้ดที่มีขนาดเล็กที่สุดที่คอมไพเลอร์ของ Rust จะพิจารณาในคราวเดียว แม้ว่าคุณจะรันคำสั่ง rustc โดยตรงไม่ใช่ cargo และส่งไฟล์ซอร์สโค้ดเพียงไฟล์เดียวเข้าไป (เหมือนที่เราทำในส่วน“พื้นฐานโปรแกรม Rust” ในบทที่ 1) คอมไพเลอร์ก็ยังจะพิจารณาว่าไฟล์ดังกล่าวเป็นเครตหนึ่ง เครตสามารถประกอบไปด้วยโมดูลต่าง ๆ และโมดูลเหล่านั้นอาจถูกกำหนดแยกไว้ในไฟล์อื่น ๆ ที่จะถูกคอมไพล์ร่วมกันกับเครตนั้นได้ ดังที่เราจะได้ศึกษาในส่วนถัด ๆ ไป
เครตสามารถแบ่งรูปแบบออกได้เป็นสองประเภทหลัก ๆ คือ เครตฐานสอง (binary crate) หรือ เครตห้องสมุด (library crate)
เครตฐานสอง (binary crates) คือโปรแกรมที่คุณสามารถคอมไพล์เป็นไฟล์ประมวลผล (executable) ที่รันใช้งานได้จริง เช่น โปรแกรมแบบบรรทัดคำสั่ง (command line) หรือระบบเซิร์ฟเวอร์ โดยแต่ละเครตจำเป็นต้องมีฟังก์ชันที่ชื่อว่า main เพื่อกำหนดสิ่งที่เกิดขึ้นเมื่อรันไฟล์ประมวลผลนั้น ซึ่งเครตทั้งหมดที่เราสร้างขึ้นมาจนถึงตอนนี้ล้วนเป็นเครตฐานสองทั้งสิ้น
เครตห้องสมุด (library crates) จะไม่มีฟังก์ชัน main และจะไม่ถูกคอมไพล์ออกมาเป็นไฟล์ประมวลผลที่รันได้โดยตรง แต่ทว่าพวกมันจะถูกกำหนดฟังก์ชันการทำงานเพื่อนำไปแบ่งปันใช้งานร่วมกับหลาย ๆ โปรเจกต์ ตัวอย่างเช่น เครต rand ที่เราเลือกใช้ในบทที่ 2 ซึ่งให้บริการความสามารถในการสุ่มตัวเลข โดยส่วนใหญ่แล้วเมื่อกลุ่มคนที่เขียนภาษา Rust (Rustaceans) พูดถึงคำว่า “เครต (crate)” มักจะสื่อความหมายถึงเครตห้องสมุด และนิยมใช้คำว่า “เครต” สลับสับเปลี่ยนไปมาแทนแนวคิดทั่วไปในการเขียนโปรแกรมอย่างคำว่า “ไลบรารี (library)”
รากเครต (crate root) คือไฟล์ซอร์สโค้ดเริ่มต้นที่คอมไพเลอร์ของ Rust จะเริ่มทำการตรวจสอบเป็นจุดแรกสุด และถือเป็นโมดูลรากของเครตของคุณ (เราจะอธิบายเกี่ยวกับโมดูลแบบเจาะลึกในส่วน“ควบคุมขอบเขตและความเป็นส่วนตัวด้วยโมดูล”)
แพ็กเกจ (package) คือกลุ่มของเครตตั้งแต่หนึ่งเครตขึ้นไปที่มารวมตัวกันเพื่อมอบคุณสมบัติการทำงานชุดหนึ่ง แพ็กเกจจะมีไฟล์ Cargo.toml บรรจุอยู่ซึ่งระบุข้อมูลวิธีการสร้างเครตเหล่านั้น อันที่จริงแล้วระบบ Cargo ก็เป็นแพ็กเกจหนึ่งที่ประกอบไปด้วยเครตฐานสองสำหรับเครื่องมือบรรทัดคำสั่งที่คุณใช้สร้างและคอมไพล์โค้ดของคุณ และแพ็กเกจ Cargo ก็ยังมีเครตห้องสมุดที่เครตฐานสองจำเป็นต้องใช้งานเชื่อมโยงอยู่ด้วย โดยโปรเจกต์อื่น ๆ ก็สามารถเลือกนำเอาเครตห้องสมุดของ Cargo นี้ไปเชื่อมโยงใช้งานตรรกะแบบเดียวกับที่เครื่องมือบรรทัดคำสั่ง Cargo ใช้งานได้เช่นกัน
แพ็กเกจสามารถจัดเก็บเครตฐานสองได้มากเท่าที่คุณต้องการ แต่ทว่าจะมีเครตห้องสมุดบรรจุอยู่ได้มากที่สุดเพียงหนึ่งเครตเท่านั้น และแพ็กเกจจำเป็นต้องมีเครตบรรจุอยู่อย่างน้อยหนึ่งเครต ไม่ว่าจะเป็นเครตห้องสมุดหรือเครตฐานสองก็ตาม
เรามาดูรายละเอียดขั้นตอนที่เกิดขึ้นเมื่อเราสั่งสร้างแพ็กเกจกัน เริ่มแรกเราจะพิมพ์คำสั่ง cargo new my-project:
$ cargo new my-project
Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs
หลังจากที่เราสั่งรัน cargo new my-project แล้ว เราจะใช้คำสั่ง ls เพื่อตรวจสอบสิ่งต่าง ๆ ที่ระบบ Cargo สรรสร้างขึ้นมา โดยภายในไดเรกทอรี my-project จะมีไฟล์ Cargo.toml ปรากฏอยู่ ซึ่งแสดงความจำนงเป็นแพ็กเกจ นอกจากนี้ยังมีไดเรกทอรี src ที่เก็บไฟล์ main.rs อยู่ด้วย เมื่อลองเปิดไฟล์ Cargo.toml ในโปรแกรมแก้ไขข้อความของคุณ จะสังเกตพบว่าไม่มีการเขียนระบุชื่อของ src/main.rs อยู่ในไฟล์เลย เนื่องจากระบบ Cargo ทำงานตามข้อตกลงร่วมกัน (convention) ว่าไฟล์ src/main.rs จะทำหน้าที่เป็นรากเครต (crate root) ของเครตฐานสองที่มีชื่อเดียวกับชื่อแพ็กเกจ ในทำนองเดียวกัน Cargo ก็จะรู้ทันทีว่าหากไดเรกทอรีของแพ็กเกจมีไฟล์ src/lib.rs บรรจุอยู่ ก็หมายความว่าแพ็กเกจดังกล่าวมีเครตห้องสมุดที่ตั้งชื่อเดียวกับชื่อแพ็กเกจ และให้ไฟล์ src/lib.rs ทำหน้าที่เป็นรากเครตของมัน โดย Cargo จะส่งผ่านไฟล์รากเครตเหล่านี้ต่อไปยัง rustc เพื่อประมวลผลสร้างเป็นห้องสมุดหรือไฟล์โปรแกรมประมวลผลจริง
ในตัวอย่างนี้ เรามีแพ็กเกจที่บรรจุเพียงไฟล์ src/main.rs เท่านั้น ซึ่งหมายความว่ามันมีเพียงเครตฐานสองชื่อ my-project เพียงเครตเดียว แต่หากในแพ็กเกจมีทั้งไฟล์ src/main.rs และ src/lib.rs ก็หมายความว่ามันมีเครตสองตัวด้วยกัน คือเครตฐานสองและเครตห้องสมุด ซึ่งทั้งคู่จะใช้ชื่อเดียวกับแพ็กเกจ นอกจากนี้แพ็กเกจสามารถบรรจุเครตฐานสองได้หลายตัวโดยการนำไฟล์เหล่านั้นไปวางไว้ในไดเรกทอรี src/bin ซึ่งแต่ละไฟล์ในนั้นจะถูกประมวลผลแยกเป็นเครตฐานสองของตนเอง