สรุป The Rust Programming Language ฉบับมือเก่า ตอนที่ 4
บทความนี้สรุปจากหนังสือ The Rust Programming Language chapter 4 ด้วยความคิดเห็นของผมเอง อาจมีการตีความที่มีโอกาสผิดพลาดได้ ทางที่ดีถ้าอยากได้ reference จริงๆแนะนำต้นทางครับ
เอาจริงๆนะตอนนี้ดีมากและใหม่มากถ้าใครยังไม่เคยอ่านเรื่อง ownership ของ Rust มาก่อนเลย
ผมล่ะอยากจะข้ามตอนนี้ไปจริงๆ เพราะคิดว่าอ่านที่ตัวต้นฉบับให้ครบทุกบรรทัดเลยน่าจะดีที่สุดแล้ว แต่ก็จะดูขี้เกียจไปนิดนึง 55 งั้นจะสรุปแบบตามความเข้าใจของตัวเองสั้นๆก็แล้วกัน
Chapter 4: Understanding Ownership
บทย่อยแรกจะพูดถึง ownership แล้วก็ background พอสมควรเลย ถ้าใครพื้นฐานเรื่อง stack และ heap แม่นๆก็อาจจะข้ามส่วนต้นๆไปได้ (แต่อ่านไว้ก็ไม่เสียหายถือว่า refresh knowledge)
เสร็จแล้วเค้าก็จะพูดถึงปัญหาว่าการที่บางภาษาต้องมาคอยนั่งจองเมมและฟรีเมมมัน error prone ทำให้พวกภาษาในอีกยุคนึงจะชอบมี GC มาคอยเก็บกวาด dangling references ที่ไม่มีใครใช้แล้ว ปัญหาก็คือเจ้า GC นี้ก็จะกิน resources ใน runtime ของเราไปด้วย (แล้ว efficiency ก็ขึ้นอยู่กับ implementation ของ GC แต่ละเจ้า)
Rust เค้าก็เลยเสนอแนวคิดที่ว่าให้ reference ถูก released ตอนที่ out of scope ไปเลยจะได้ไม่ต้องมานั่ง manual และก็ไม่ต้องไปพึ่ง GC
พอแบบนี้ก็อาจจะมี challenge ว่าถ้ามีหลายๆ references ที่ point ไปที่ address เดียวกัน การ release หลายๆครั้งก็เกิดปัญหาอีก ก็เลยเกิดเป็นแนวคิดที่ว่า
ให้แต่ละ heap value มี owner ได้คนเดียว (ณ เวลาๆหนึ่ง)
จริงๆ concept หลักๆของ ownership (ที่ผมเข้าใจ) ก็แค่ประมาณนี้เลย เวลาตัว heap value ถูก assign ไปที่ variable อื่น Rust ก็จะย้าย ownership ไปที่ variable นั้นๆ (เรียก operation นี้ว่า move) แล้วถ้า variable นั้น goes out of the scope ทาง Rust ก็จะ “drop” ตัว heap value ที่มัน owns อยู่
ทีนี้การ pass arguments ผ่าน function calling เช่น func(a_string)
ถ้า pass heap value ไปปกติแบบนี้ มันก็คือการ assign heap value นั้นให้กับ parameter ของ function ซึ่ง ownership ก็จะถูก moved แปลว่าถ้า function scope นั้นจบไปแล้วตัว heap value ก็จะถูก dropped ทำให้ใน scope ของ caller บรรทัดหลังจากนั้นจะไม่สามารถใช้ variable a_string
ที่เป็นเจ้าของเก่าของ heap value นั้นได้อีกแล้ว
ซึ่งบางครั้งเราอาจจะไม่ได้ต้องการแบบนั้น Rust ก็เลยอนุณาตให้เราแค่ pass “reference” ของ heap value นั้นไปได้ แต่ ownership จะยังคงอยู่ที่ variable ตัวเดิมซึ่ง Rust เรียกเรื่องนี้ว่า
References (หรือ Borrowing)
ก็สามารถทำได้โดยใช้ func(&a_string)
(เพิ่ม &
เข้าไป)
reference by default ก็เป็น immutable ตามปกติ แต่ถ้าอยากจะให้เป็น mutable ก็ต้องบอกด้วยไม่งั้น compiler ด่านะ func(&mut a_string)
นอกจากนี้ยังสามารถมี immutable references กี่ตัวก็ได้ต่อ heap value เพราะถ้าแค่อ่านก็ไม่มีปัญหา แต่ถ้าสร้าง mutable reference จะสามารถมีได้แค่ reference เดียว (ไม่ใช่แค่ mut reference เดียว แต่ reference เดียวโดดๆเลย ไม่สามารถมี immutable references ร่วมด้วยได้ในขณะเดียวกับที่มี mutable reference เพื่อป้องกันกรณีที่ค่าของ reference โดนเปลี่ยนแล้ว immutable references ไม่ได้ aware of)
บทย่อยสุดท้ายก็พูดถึง reference อีกแบบก็คือ
Slice type
เป็นวิธีสร้าง reference เหมือนข้างบนนั่นแหล่ะ แต่เป็นการเล่นกับบางส่วนของพวก collection type ต่างๆ
เช่น let hello = &s[0..5];
แบบนี้ hello
ก็จะเก็บ immutable reference ของตัวแปร s
ไว้ตั้งแต่ index 0 ถึง 4
ทำนองเดียวกับ array ก็สามารถทำได้คล้ายๆกัน
จบแล้วครับบทที่ 4 (ผมยังคง highly recommend ให้ไปอ่าน original content นะครับเพราะค่อนข้างเป็นของใหม่ 555)