7 คะแนน โดย GN⁺ 2025-05-07 | 4 ความคิดเห็น | แชร์ทาง WhatsApp
  • ผู้เขียนซึ่งใช้ C++ มานานกว่า 20 ปี ได้แนะนำจุดเปลี่ยนที่ทำให้ ค้นพบข้อดีของ Rust อีกครั้ง ผ่านการบรรยายของ Matt Godbolt
  • ใน C++ นั้น ความผิดพลาดจากการสับสนชนิดข้อมูล มักไม่ถูกคอมไพเลอร์ตรวจจับได้อย่างเหมาะสม แต่ Rust จะ ป้องกันอย่างเข้มงวดตั้งแต่คอมไพล์ไทม์
  • Rust ไม่ได้มีดีแค่ ความปลอดภัยของหน่วยความจำ เท่านั้น แต่ยังมีการออกแบบที่เอื้อต่อ การป้องกันการใช้งาน API ผิดวิธี ด้วย
  • โดยเฉพาะในการจัดการอินพุตขณะรันไทม์ Rust จะ บังคับให้จัดการข้อผิดพลาดอย่างชัดเจน เพื่อลดความเสี่ยง
  • ท้ายที่สุด นี่เป็นกรณีตัวอย่างที่แสดงให้เห็นว่า การออกแบบภาษาเป็นเครื่องมือทรงพลังในการป้องกันความผิดพลาดของนักพัฒนา ได้

บทนำ

  • การบรรยายของ Matt Godbolt ชื่อ "Correct by Construction" ชี้ให้เห็นถึง ปัญหาในการออกแบบ API ของ C++ ซึ่งสอดคล้องกับปรัชญาของ Rust ด้วย
  • การบรรยายนี้เป็นสื่อเริ่มต้นที่ดีสำหรับการทำความเข้าใจจุดแข็งของ Rust

What's in a type — ข้อจำกัดของ C++

  • ฟังก์ชันซิกเนเจอร์อย่าง void sendOrder(const char *symbol, bool buy, int quantity, double price) นั้น เสี่ยงต่อความผิดพลาดอย่างมาก
  • หากใช้เพียงชนิดข้อมูลพื้นฐานอย่าง bool, int, double คอมไพเลอร์จะ ไม่เตือนแม้ใส่ชนิดข้อมูลผิด
  • type alias อย่าง using Price = double ไม่ได้มีความสามารถในการแยกชนิดข้อมูลจริง
  • เมื่อใช้คลาสและตัวสร้าง explicit เพื่อสร้าง Quantity, Price คอมไพเลอร์จะช่วยจับข้อผิดพลาดบางส่วนได้ แต่:
    • ยังยอมให้ใช้ค่าติดลบได้ ซึ่งจะกลายเป็นปัญหาเฉพาะตอนรันไทม์
    • สามารถใช้ static_assert และเทมเพลตเพื่อบังคับ การตรวจสอบตั้งแต่คอมไพล์ไทม์ ได้
    • แต่การแปลงค่าขณะรันไทม์อย่าง atoi ก็ยัง ก่อให้เกิด integer overflow ได้ และคอมไพเลอร์ไม่สามารถตรวจจับได้

Rust ต่างออกไปอย่างไร?

  • แม้จะเป็นนิยามฟังก์ชันแบบเดียวกัน Rust ก็สามารถแสดงข้อผิดพลาดเรื่อง ชนิดข้อมูลไม่ตรงกัน ได้อย่างชัดเจนตั้งแต่ขั้นตอนคอมไพล์
  • การนิยาม ชนิดข้อมูลใหม่ อย่าง struct Price(pub f64); struct Quantity(pub u64); ก็ทำได้ง่าย และยัง ป้องกันอินพุตค่าติดลบ ได้อย่างเป็นธรรมชาติ
  • การแปลงสตริงขณะรันไทม์อย่าง &quot;string&quot;.parse::<u64>() ก็จำเป็นต้องมี การจัดการข้อผิดพลาดแบบชัดเจน
  • หากใช้ .expect() เพื่อ unwrap ค่าแบบบังคับ ก็อาจทำให้โปรแกรมล่มตอนรันไทม์ได้ แต่ยังถูกเน้นว่า ดีกว่าความผิดพลาดเงียบ ๆ ใน C++

สรุป

  • Rust ปกป้องนักพัฒนาไม่ใช่แค่ด้วยความเสถียรของหน่วยความจำ แต่ยังผ่าน การป้องกันการใช้ API ผิดวิธี, การตรวจสอบตั้งแต่คอมไพล์ไทม์, และระบบชนิดข้อมูลที่ชัดเจน
  • สิ่งนี้แสดงให้เห็นว่า พลังของการออกแบบภาษา สามารถช่วยป้องกันความผิดพลาดของนักพัฒนาได้ตั้งแต่ต้นทาง
  • ผู้เริ่มต้น Rust อาจต้องเผชิญกับความยากจาก borrow checker แต่ปัญหานี้จะค่อย ๆ คลี่คลายไปเมื่อเวลาผ่านไป
  • แม้ C++ จะพัฒนามาอย่างมากในเชิงประวัติศาสตร์ แต่ก็ยังเห็นได้ชัดว่า ยากที่จะมอบความปลอดภัยและความชัดเจนในระดับพื้นฐานแบบเดียวกับ Rust

อ้างอิง

4 ความคิดเห็น

 
cronex 2025-05-08

ดูเหมือนว่าส่วนใหญ่ของสิ่งที่มักถูกยกมาเป็นข้อเสียของ C++ นั้น ส่วนมากเป็นสิ่งที่ยังคงไว้เพราะความเข้ากันได้กับภาษา C
จะสามารถปรับเปลี่ยนให้พัฒนาโดยละทิ้งความเข้ากันได้กับ C ได้ไหม?

 
coremaker 2025-05-08

คงจะดีกว่านี้ถ้าไม่มี unsafe ให้ใช้เสียเลย

 
codemasterkimc 2025-05-08

ภาษาต้นตำรับ = Rust

 
GN⁺ 2025-05-07
ความคิดเห็นจาก Hacker News
  • ข้อดีใหญ่ที่สุดของ Rust คือการใช้ Result type ที่ทำให้รูปแบบการส่งต่อข้อผิดพลาดเป็นแบบเดียวกัน จึงไม่ต้องคอยกังวลกับการจัดการ exception หรือรูปแบบการคืนค่าข้อผิดพลาดที่หลากหลาย

    • ด้วยตัวลัด ? และ functional interface ของ Result ทำให้การจัดการข้อผิดพลาดทั้งสนุกและรับมือได้ง่าย
    • เมื่อเทียบกับวิธีจัดการข้อผิดพลาดอันซับซ้อนของ C++ สิ่งที่น่าหงุดหงิดคือความขาดความสม่ำเสมอ
  • มีความไม่พอใจกับ C++ อยู่มาก โดยเฉพาะประเด็นที่ต้องจำกฎจำนวนมาก และถ้าพลาดแม้เพียงข้อเดียว โค้ดก็อาจเปราะบางได้

    • เพื่อเพิ่มความปลอดภัยของ C++ จำเป็นต้องมีแนวทางที่คล้ายกับวิธีที่ปลอดภัยของ Rust
  • โค้ด C++ ที่เขียนอยู่ตอนนี้มีลักษณะคล้าย Rust ใช้ type ที่ชัดเจนและแข็งแรง รวมถึงการจัดการอายุการใช้งานที่ชัดเจน

    • Rust compiler ช่วยจับบั๊กและรายงานข้อผิดพลาดได้ดีกว่า
  • ปัญหา implicit conversion ของ C++ เป็นปัญหาของไลบรารีมากกว่าของตัวภาษา

    • ใน C++ ก็สามารถทำฟีเจอร์คล้าย Rust ได้ แต่ต้องอาศัยการรองรับจากไลบรารี
  • Rust ไม่มี keyword arguments หรือ tuple ที่มีชื่อ ทำให้การใช้โครงสร้าง Args/Options ไม่ค่อยสะดวก

  • ตัวเลือก -Wconversion สามารถจับปัญหาการแปลงค่าบางประเภทได้ แต่ใช้ไม่ได้กับทุกกรณี

    • ตัวอย่างเช่น การแปลง 1000.0 เป็น 1000 จะถือว่าไม่มีการสูญเสียความแม่นยำ
  • จุดที่ Rust ดีกว่าคือไม่มีการแปลงตัวเลขแบบ implicit ใน C++ ควรหลีกเลี่ยง atoi และใช้ฟังก์ชันแปลงค่าของ STL แทน

  • ฟีเจอร์ที่คล้ายกับข้อจำกัดของ SQL หรือ custom type และ validator ของ pydantic ยังไม่มีใน Rust หรือ Golang

  • ถ้าสนใจพอดแคสต์โปรแกรมมิง "Two's Complement" ของ Matt และ Ben Rady ก็ถือว่าน่าลองฟัง