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

สวัสดี, Cargo!

Cargo คือระบบการคอมไพล์ (build system) และตัวจัดการแพ็กเกจ (package manager) ของภาษา Rust ชาว Rustacean ส่วนใหญ่ใช้เครื่องมือนี้ในการจัดการโปรเจกต์ Rust ของตนเอง เนื่องจาก Cargo ช่วยจัดการงานต่างๆ ให้คุณเป็นจำนวนมาก เช่น การคอมไพล์โค้ดของคุณ, การดาวน์โหลดไลบรารีที่โค้ดของคุณจำเป็นต้องใช้งาน และการคอมไพล์ไลบรารีเหล่านั้น (เราเรียกไลบรารีที่โค้ดของคุณจำเป็นต้องใช้งานว่า ไลบรารีที่ต้องใช้พึ่งพา (dependencies))

โปรแกรม Rust ที่ง่ายที่สุดอย่างโปรแกรมที่เราเพิ่งเขียนไปนั้นไม่มีไลบรารีที่ต้องใช้พึ่งพาใดๆ เลย หากเราสร้างโปรเจกต์ “Hello, world!” ด้วย Cargo มันจะใช้เพียงแค่ส่วนของ Cargo ที่มีหน้าที่จัดการการคอมไพล์โค้ดของคุณเท่านั้น เมื่อคุณเขียนโปรแกรม Rust ที่มีความซับซ้อนมากขึ้น คุณจะได้เพิ่มไลบรารีที่ต้องใช้พึ่งพาเข้าไป และถ้าหากคุณเริ่มโปรเจกต์โดยใช้ Cargo การเพิ่มไลบรารีที่ต้องใช้พึ่งพาก็จะทำได้ง่ายขึ้นมาก

เนื่องจากโปรเจกต์ Rust ส่วนใหญ่ใช้ Cargo เนื้อหาในส่วนที่เหลือของหนังสือเล่มนี้จึงถือว่าคุณใช้งาน Cargo เช่นกัน Cargo จะถูกติดตั้งมาพร้อมกับ Rust หากคุณใช้ตัวติดตั้งอย่างเป็นทางการตามที่อธิบายไว้ในหัวข้อ “การติดตั้ง” แต่ถ้าคุณติดตั้ง Rust ด้วยวิธีอื่น ให้ตรวจสอบว่า Cargo ถูกติดตั้งไว้หรือไม่โดยป้อนคำสั่งต่อไปนี้ในเทอร์มินัลของคุณ:

$ cargo --version

หากคุณเห็นหมายเลขเวอร์ชัน แสดงว่าคุณมีมันแล้ว! หากคุณเห็นข้อผิดพลาด เช่น command not found ให้ดูเอกสารประกอบสำหรับวิธีการติดตั้งของคุณเพื่อตรวจสอบวิธีการติดตั้ง Cargo แยกต่างหาก

การสร้างโปรเจกต์ด้วย Cargo

มาสร้างโปรเจกต์ใหม่โดยใช้ Cargo และดูว่ามันแตกต่างจากโปรเจกต์ “Hello, world!” เดิมของเราอย่างไร ย้อนกลับไปยังไดเรกทอรี projects ของคุณ (หรือที่ใดก็ตามที่คุณเลือกเก็บโค้ดไว้) จากนั้น ไม่ว่าจะบนระบบปฏิบัติการใด ให้รันคำสั่งต่อไปนี้:

$ cargo new hello_cargo
$ cd hello_cargo

คำสั่งแรกจะสร้างไดเรกทอรีและโปรเจกต์ใหม่ชื่อว่า hello_cargo เราตั้งชื่อโปรเจกต์ของเราว่า hello_cargo และ Cargo จะสร้างไฟล์ต่างๆ ไว้ในไดเรกทอรีที่มีชื่อเดียวกัน

เข้าไปในไดเรกทอรี hello_cargo แล้วแสดงรายการไฟล์ คุณจะเห็นว่า Cargo ได้สร้างสองไฟล์และหนึ่งไดเรกทอรีให้กับเรา นั่นคือไฟล์ Cargo.toml และไดเรกทอรี src ที่มีไฟล์ main.rs อยู่ข้างใน

นอกจากนี้ยังได้ทำการสร้าง Git repository ใหม่ขึ้นมาพร้อมกับไฟล์ .gitignore ด้วย ทั้งนี้ไฟล์ Git จะไม่ถูกสร้างขึ้นหากคุณรันคำสั่ง cargo new ภายใต้ Git repository ที่มีอยู่แล้ว แต่คุณสามารถข้ามข้อกำหนดนี้ได้โดยการใช้คำสั่ง cargo new --vcs=git

หมายเหตุ: Git คือระบบควบคุมเวอร์ชัน (version control system) ที่นิยมใช้กันทั่วไป คุณสามารถเปลี่ยนให้ cargo new ใช้ระบบควบคุมเวอร์ชันอื่น หรือไม่ใช้ระบบควบคุมเวอร์ชันเลยก็ได้ โดยใช้แฟล็ก --vcs รันคำสั่ง cargo new --help เพื่อดูตัวเลือกที่มีทั้งหมด

เปิดไฟล์ Cargo.toml ด้วยโปรแกรมแก้ไขข้อความที่คุณต้องการ มันควรจะดูคล้ายกับโค้ดในรายการที่ 1-2

[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2024"

[dependencies]

ไฟล์นี้อยู่ในรูปแบบ TOML (Tom’s Obvious, Minimal Language) ซึ่งเป็นรูปแบบไฟล์กำหนดค่า (configuration format) ของ Cargo

บรรทัดแรก [package] คือหัวข้อส่วน (section heading) ซึ่งระบุว่าข้อความหลังจากนี้เป็นการกำหนดค่าของแพ็กเกจ เมื่อเราเพิ่มข้อมูลเข้าไปในไฟล์นี้มากขึ้น เราจะได้เพิ่มส่วน (section) อื่นๆ เข้าไปด้วย

สามบรรทัดถัดมาเป็นการกำหนดค่าข้อมูลที่ Cargo จำเป็นต้องใช้ในการคอมไพล์โปรแกรมของคุณ ได้แก่ ชื่อ, เวอร์ชัน และเอดิชัน (edition) ของ Rust ที่จะใช้ เราจะอธิบายเกี่ยวกับคีย์ edition ใน ภาคผนวก E

บรรทัดสุดท้าย [dependencies] คือจุดเริ่มต้นของส่วนระบุรายการไลบรารีที่ต้องใช้พึ่งพาของโปรเจกต์ ในภาษา Rust แพ็กเกจของโค้ดจะถูกเรียกว่า เครต (crates) เรายังไม่จำเป็นต้องใช้เครตอื่นๆ ในโปรเจกต์นี้ แต่เราจะได้ใช้ในโปรเจกต์แรกของบทที่ 2 ดังนั้นเราจะมาใช้ส่วนของ dependencies นี้ในตอนนั้น

ตอนนี้ให้เปิดไฟล์ src/main.rs แล้วลองมาดูกัน:

Filename: src/main.rs

fn main() {
    println!("Hello, world!");
}

Cargo ได้สร้างโปรแกรม “Hello, world!” ให้กับคุณเรียบร้อยแล้ว เช่นเดียวกับโปรแกรมที่เราเขียนไว้ในรายการที่ 1-1! จนถึงตอนนี้ สิ่งที่แตกต่างระหว่างโปรเจกต์ของเรากับโปรเจกต์ที่ Cargo สร้างขึ้นก็คือ Cargo นำโค้ดไปใส่ไว้ในไดเรกทอรี src และเรามีไฟล์กำหนดค่า Cargo.toml อยู่ในไดเรกทอรีระดับบนสุด

Cargo คาดหวังว่าไฟล์ซอร์สโค้ดของคุณจะอยู่ภายในไดเรกทอรี src ส่วนไดเรกทอรีโปรเจกต์ระดับบนสุดนั้นมีไว้สำหรับไฟล์ README, ข้อมูลใบอนุญาต (license), ไฟล์กำหนดค่า และสิ่งอื่นๆ ที่ไม่เกี่ยวข้องกับโค้ดของคุณ การใช้ Cargo จะช่วยจัดระเบียบโปรเจกต์ของคุณ ทุกๆ สิ่งจะมีที่ทางของตัวเอง และทุกๆ สิ่งจะอยู่ในที่ที่ควรอยู่

หากคุณเริ่มโปรเจกต์ที่ไม่ได้ใช้ Cargo เหมือนอย่างโปรเจกต์ “Hello, world!” ก่อนหน้านี้ คุณสามารถแปลงให้เป็นโปรเจกต์ที่ใช้ Cargo ได้ โดยย้ายโค้ดโปรเจกต์เข้าไปในไดเรกทอรี src แล้วสร้างไฟล์ Cargo.toml ที่เหมาะสม วิธีง่ายๆ ในการสร้างไฟล์ Cargo.toml ดังกล่าวคือการรันคำสั่ง cargo init ซึ่งจะสร้างมันขึ้นมาให้คุณโดยอัตโนมัติ

การคอมไพล์และการรันโปรเจกต์ Cargo

ทีนี้มาดูกันว่ามีอะไรแตกต่างไปบ้างเมื่อเราคอมไพล์และรันโปรแกรม “Hello, world!” ด้วย Cargo! จากไดเรกทอรี hello_cargo ของคุณ ให้คอมไพล์โปรเจกต์ด้วยการพิมพ์คำสั่งดังต่อไปนี้:

$ cargo build
   Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs

คำสั่งนี้จะสร้างไฟล์โปรแกรมที่รันได้ (executable file) ขึ้นมาใน target/debug/hello_cargo (หรือ target\debug\hello_cargo.exe บน Windows) แทนที่จะอยู่ในไดเรกทอรีปัจจุบันของคุณ เนื่องจากค่าเริ่มต้นจะเป็นการคอมไพล์แบบดีบั๊ก (debug build) Cargo จึงเก็บไฟล์ไบนารีไว้ในไดเรกทอรีชื่อว่า debug คุณสามารถรันโปรแกรมดังกล่าวได้ด้วยคำสั่งนี้:

$ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows
Hello, world!

หากทุกอย่างเป็นไปด้วยดี คำว่า Hello, world! ควรจะแสดงขึ้นมาบนเทอร์มินัล การรัน cargo build เป็นครั้งแรกจะทำให้ Cargo สร้างไฟล์ใหม่ขึ้นมาในไดเรกทอรีระดับบนสุดด้วย นั่นคือไฟล์ Cargo.lock ไฟล์นี้ใช้เพื่อติดตามเวอร์ชันที่แน่นอนของไลบรารีที่ต้องใช้พึ่งพาในโปรเจกต์ของคุณ เนื่องจากโปรเจกต์นี้ยังไม่มีไลบรารีที่ต้องใช้พึ่งพา ไฟล์นี้จึงค่อนข้างว่างเปล่า คุณไม่จำเป็นต้องแก้ไขไฟล์นี้ด้วยตนเองแต่อย่างใด เนื่องจาก Cargo จะคอยจัดการเนื้อหาภายในให้คุณเอง

เราเพิ่งจะคอมไพล์โปรเจกต์ด้วยคำสั่ง cargo build และรันด้วย ./target/debug/hello_cargo แต่เราก็ยังสามารถใช้คำสั่ง cargo run เพื่อคอมไพล์โค้ดและรันโปรแกรมที่ได้ทั้งหมดในคำสั่งเดียวได้เช่นกัน:

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/hello_cargo`
Hello, world!

การใช้งาน cargo run นั้นสะดวกกว่าการที่ต้องคอยจำว่าต้องรัน cargo build แล้วค่อยรันผ่านพาธของไฟล์ไบนารีทั้งหมด ดังนั้นนักพัฒนาส่วนใหญ่จึงนิยมใช้งาน cargo run

โปรดสังเกตว่าในครั้งนี้เราจะไม่เห็นผลลัพธ์ที่แสดงว่า Cargo กำลังคอมไพล์ hello_cargo เนื่องจาก Cargo ทราบว่าไม่มีไฟล์ใดเปลี่ยนแปลง จึงไม่ได้คอมไพล์ใหม่และเพียงแค่รันไฟล์ไบนารีเท่านั้น หากคุณมีการแก้ไขซอร์สโค้ด Cargo จะคอมไพล์โปรเจกต์ใหม่ก่อนที่จะรัน และคุณจะเห็นผลลัพธ์ลักษณะนี้:

$ cargo run
   Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs
     Running `target/debug/hello_cargo`
Hello, world!

นอกจากนี้ Cargo ยังมีคำสั่งชื่อ cargo check ด้วย คำสั่งนี้จะตรวจสอบโค้ดของคุณอย่างรวดเร็วเพื่อให้แน่ใจว่ามันสามารถคอมไพล์ได้สำเร็จ แต่จะไม่สร้างไฟล์ที่รันได้ออกมา:

$ cargo check
   Checking hello_cargo v0.1.0 (file:///projects/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs

ทำไมคุณถึงไม่ต้องการไฟล์ที่รันได้ล่ะ? บ่อยครั้งที่คำสั่ง cargo check จะทำงานเร็วกว่า cargo build มาก เนื่องจากมันข้ามขั้นตอนการสร้างไฟล์โปรแกรมที่รันได้ไป หากคุณกำลังตรวจสอบการทำงานของคุณไปเรื่อยๆ ในขณะที่เขียนโค้ด การใช้ cargo check จะช่วยเร่งกระบวนการทำให้คุณทราบว่าโปรเจกต์ของคุณยังคงคอมไพล์ผ่านอยู่หรือไม่! ด้วยเหตุนี้ ชาว Rustacean หลายคนจึงรันคำสั่ง cargo check เป็นระยะๆ ระหว่างเขียนโปรแกรมเพื่อความแน่ใจว่าโปรแกรมคอมไพล์ผ่าน จากนั้นจึงรัน cargo build เมื่อพร้อมที่จะใช้งานไฟล์โปรแกรมที่รันได้

มาสรุปสิ่งที่เราได้เรียนรู้เกี่ยวกับ Cargo กันอีกครั้ง:

  • เราสามารถสร้างโปรเจกต์ได้โดยใช้คำสั่ง cargo new
  • เราสามารถคอมไพล์โปรเจกต์ได้โดยใช้คำสั่ง cargo build
  • เราสามารถคอมไพล์และรันโปรเจกต์ได้ในขั้นตอนเดียวโดยใช้คำสั่ง cargo run
  • เราสามารถตรวจสอบหาข้อผิดพลาดในโปรเจกต์โดยไม่ต้องสร้างไฟล์ไบนารีได้โดยใช้คำสั่ง cargo check
  • แทนที่จะบันทึกผลลัพธ์การคอมไพล์ไว้ในไดเรกทอรีเดียวกับโค้ดของเรา Cargo จะเก็บมันไว้ในไดเรกทอรี target/debug แทน

ข้อดีเพิ่มเติมของการใช้ Cargo ก็คือ คำสั่งต่างๆ จะเหมือนกันทั้งหมดไม่ว่าคุณจะทำงานอยู่บนระบบปฏิบัติการใด ดังนั้นนับจากจุดนี้เป็นต้นไป เราจะไม่ลงรายละเอียดแยกตามระบบปฏิบัติการระหว่าง Linux/macOS กับ Windows อีก

การคอมไพล์เพื่อใช้งานจริง (Release)

เมื่อโปรเจกต์ของคุณพร้อมสำหรับการนำไปใช้งานจริงแล้ว คุณสามารถใช้คำสั่ง cargo build --release เพื่อคอมไพล์โปรเจกต์พร้อมการปรับประสิทธิภาพให้เหมาะสมที่สุด (optimizations) คำสั่งนี้จะสร้างไฟล์ที่รันได้ใน target/release แทนที่จะเป็น target/debug การเปิดใช้ตัวเลือกปรับประสิทธิภาพจะทำให้โค้ด Rust ของคุณทำงานได้เร็วขึ้น แต่จะส่งผลให้โปรแกรมใช้เวลาคอมไพล์นานขึ้นด้วย นี่จึงเป็นเหตุผลที่มีการแบ่งโปรไฟล์การทำงานเป็นสองแบบ: แบบแรกสำหรับขั้นตอนการพัฒนา เมื่อคุณต้องการคอมไพล์ใหม่ซ้ำๆ ได้อย่างรวดเร็ว และอีกแบบสำหรับตอนสร้างโปรแกรมสุดท้ายที่จะส่งมอบให้แก่ผู้ใช้งาน ซึ่งจะไม่ต้องถูกคอมไพล์ซ้ำอีกแล้วและต้องการให้รันได้เร็วที่สุด หากคุณกำลังวัดประสิทธิภาพเวลาในการทำงานของโค้ด (benchmarking) อย่าลืมรันคำสั่ง cargo build --release และทดสอบผ่านไฟล์ที่รันได้ในโฟลเดอร์ target/release

การใช้ประโยชน์จากข้อกำหนดตกลงร่วมกันของ Cargo

สำหรับโปรเจกต์ง่ายๆ Cargo อาจจะไม่ได้มอบประโยชน์ที่แตกต่างไปจากปรกติมากนักเมื่อเทียบกับการใช้เพียง rustc ตรงๆ แต่จะเริ่มเห็นความคุ้มค่าได้อย่างชัดเจนเมื่อโปรแกรมของคุณเริ่มมีความซับซ้อนมากขึ้น เมื่อโปรแกรมเติบโตจนมีหลายๆ ไฟล์ หรือจำเป็นต้องใช้ไลบรารีภายนอก การปล่อยให้ Cargo คอยประสานงานและดูแลการคอมไพล์โปรเจกต์จะทำได้สะดวกกว่ามาก

แม้ว่าโปรเจกต์ hello_cargo จะดูเรียบง่าย แต่ ณ ตอนนี้มันก็ได้ใช้เครื่องมือทำงานจริงส่วนใหญ่ที่คุณจะได้นำไปใช้ตลอดการทำงานกับภาษา Rust ของคุณเลยทีเดียว อันที่จริงแล้วในการเริ่มต้นพัฒนาต่อจากโปรเจกต์เดิมที่มีอยู่ คุณสามารถใช้คำสั่งต่อไปนี้เพื่อดึงโค้ดลงมาผ่าน Git, เปลี่ยนเข้าไปยังไดเรกทอรีโปรเจกต์นั้น แล้วจึงสั่งคอมไพล์ได้เลย:

$ git clone example.org/someproject
$ cd someproject
$ cargo build

หากต้องการข้อมูลเพิ่มเติมเกี่ยวกับ Cargo สามารถเข้าไปดูได้ที่ เอกสารประกอบการใช้งานของ Cargo

สรุป

คุณได้เริ่มต้นเดินทางสู่การเรียนรู้ภาษา Rust ได้อย่างยอดเยี่ยมแล้ว! ในบทนี้ คุณได้เรียนรู้วิธีการ:

  • ติดตั้ง Rust เวอร์ชันเสถียร (stable) ล่าสุด โดยใช้ rustup
  • อัปเดต Rust ให้เป็นเวอร์ชันใหม่กว่า
  • เปิดเอกสารประกอบคู่มือที่ติดตั้งอยู่บนเครื่องของคุณ
  • เขียนและรันโปรแกรม “Hello, world!” โดยใช้ตัวคอมไพล์ rustc โดยตรง
  • สร้างและรันโปรเจกต์ใหม่ตามข้อกำหนดตกลงร่วมกันของ Cargo

นี่เป็นช่วงเวลาที่ดีในการสร้างโปรแกรมที่มีความหมายและซับซ้อนขึ้นอีกเล็กน้อยเพื่อให้คุ้นชินกับการอ่านและเขียนโค้ด Rust ดังนั้นในบทที่ 2 เราจะมาเขียนโปรแกรมเกมทายตัวเลขกัน แต่หากคุณอยากจะเริ่มต้นด้วยการเรียนรู้ว่าแนวคิดการเขียนโปรแกรมทั่วไปทำงานอย่างไรใน Rust ก่อน ให้ไปดูในบทที่ 3 แล้วค่อยย้อนกลับมาที่บทที่ 2