พอยน์เตอร์อัจฉริยะ (Smart Pointers)
พอยน์เตอร์ (Pointer) เป็นแนวคิดทั่วไปสำหรับตัวแปรที่บรรจุที่อยู่ (address) ในหน่วยความจำ โดยที่อยู่นี้จะอ้างอิงถึง หรือ “ชี้ไปที่” ข้อมูลอื่น ชนิดพอยน์เตอร์ที่พบบ่อยที่สุดใน Rust คือ การอ้างอิง (reference) ซึ่งคุณได้เรียนรู้ไปแล้วในบทที่ 4 การอ้างอิงจะระบุด้วยสัญลักษณ์ & และทำการยืมค่าที่มันชี้ไป พวกมันไม่มีความสามารถพิเศษอื่นใดนอกจากการอ้างอิงถึงข้อมูล และไม่มีภาระส่วนเกิน (overhead)
ในทางกลับกัน พอยน์เตอร์อัจฉริยะ (Smart pointers) คือโครงสร้างข้อมูลที่ทำหน้าที่เหมือนพอยน์เตอร์ แต่ก็มีข้อมูลอธิบาย (metadata) และความสามารถเพิ่มเติม แนวคิดเรื่องพอยน์เตอร์อัจฉริยะไม่ได้มีแค่ใน Rust เท่านั้น พอยน์เตอร์อัจฉริยะมีต้นกำเนิดมาจาก C++ และมีอยู่ในภาษาอื่น ๆ เช่นกัน Rust มีพอยน์เตอร์อัจฉริยะหลากหลายชนิดที่นิยามไว้ในไลบรารีมาตรฐาน ซึ่งมอบคุณสมบัติการทำงานนอกเหนือไปจากสิ่งที่การอ้างอิงทั่วไปมอบให้ เพื่อสำรวจแนวคิดทั่วไปนี้ เราจะดูตัวอย่างต่าง ๆ ของพอยน์เตอร์อัจฉริยะ รวมถึงชนิดพอยน์เตอร์อัจฉริยะแบบนับจำนวนการอ้างอิง (reference counting) พอยน์เตอร์ชนิดนี้ช่วยให้คุณยินยอมให้ข้อมูลมีเจ้าของหลายคนได้โดยการติดตามจำนวนเจ้าของ และเมื่อไม่เหลือเจ้าของแล้ว ก็จะทำการล้างข้อมูลนั้นออก
ใน Rust ด้วยแนวคิดเรื่องความเป็นเจ้าของและการยืม มีความแตกต่างเพิ่มเติมระหว่างการอ้างอิงและพอยน์เตอร์อัจฉริยะคือ ในขณะที่การอ้างอิงจะยืมเฉพาะข้อมูล ในหลาย ๆ กรณีพอยน์เตอร์อัจฉริยะจะเป็นเจ้าของ (own) ข้อมูลที่พวกมันชี้ไป
พอยน์เตอร์อัจฉริยะมักจะถูกประยุกต์ใช้งานโดยใช้ struct ต่างจาก struct ทั่วไป ตรงที่พอยน์เตอร์อัจฉริยะจะประยุกต์ใช้เทรต Deref และ Drop เทรต Deref ช่วยให้อินสแตนซ์ของ struct พอยน์เตอร์อัจฉริยะทำตัวเหมือนการอ้างอิงได้ เพื่อให้คุณสามารถเขียนโค้ดเพื่อทำงานได้ทั้งกับการอ้างอิงหรือพอยน์เตอร์อัจฉริยะ เทรต Drop ช่วยให้คุณปรับแต่งโค้ดที่รันเมื่ออินสแตนซ์ของพอยน์เตอร์อัจฉริยะหลุดออกจากขอบเขต (scope) ในบทนี้ เราจะพูดถึงเทรตทั้งสองนี้และแสดงให้เห็นว่าเหตุใดพวกมันจึงมีความสำคัญต่อพอยน์เตอร์อัจฉริยะ
เนื่องจากรูปแบบพอยน์เตอร์อัจฉริยะเป็นรูปแบบการออกแบบทั่วไปที่ใช้บ่อยใน Rust บทนี้จะไม่ครอบคลุมพอยน์เตอร์อัจฉริยะที่มีอยู่ทั้งหมด ไลบรารีหลายแห่งมีพอยน์เตอร์อัจฉริยะของตนเอง และคุณยังสามารถเขียนขึ้นเองได้ด้วย เราจะครอบคลุมพอยน์เตอร์อัจฉริยะที่พบบ่อยที่สุดในไลบรารีมาตรฐาน:
Box<T>, สำหรับการจัดสรรค่าบนฮีป (heap)Rc<T>, ชนิดข้อมูลนับจำนวนการอ้างอิงที่ช่วยให้มีความเป็นเจ้าของหลายคนได้Ref<T>และRefMut<T>, เข้าถึงผ่านRefCell<T>ซึ่งเป็นชนิดข้อมูลที่บังคับใช้กฎการยืมขณะรันไทม์แทนที่จะเป็นขณะคอมไพล์
นอกจากนี้ เราจะครอบคลุมรูปแบบการแก้ไขภายใน (interior mutability) ซึ่งเป็นชนิดข้อมูลที่ไม่สามารถแก้ไขได้ แต่เปิดเผย API สำหรับการแก้ไขค่าภายในได้ เราจะพูดถึงวงจรการอ้างอิง (reference cycles) ด้วยเช่นกัน: ว่าพวกมันทำให้เกิดหน่วยความจำรั่วไหล (memory leak) ได้อย่างไร และจะป้องกันได้อย่างไร
มาลุยกันเลย!