Rust Vec::spare_capacity_mut: เติม buffer ที่จองไว้โดยไม่สร้าง Vec ชั่วคราว
Vec::spare_capacity_mut ให้เราเห็นช่องที่จองไว้แต่ยังไม่มีค่าในรูป MaybeUninit<T> เหมือนโกดังที่ตีเส้นช่องว่างไว้แล้วครับ เราวางของลงแต่ละช่องได้โดยไม่สร้าง Vec กลาง แต่ต้องแจ้งจำนวนช่องที่วางสำเร็จด้วย set_len อย่างแม่นยำ
WHY: ใช้เมื่อ producer เขียนลงปลาย Vec ได้ตรง ๆ
API นี้เหมาะกับ parser, decoder หรือ FFI ที่เขียนค่าเป็นชุดและวัดแล้วว่าการ copy สำคัญ จุดอันตรายไม่ใช่ write แต่คือการประกาศ length เกินจำนวนค่าที่ initialize แล้ว เพราะ Rust จะเชื่อว่าทุกช่องใน length พร้อมถูกอ่านและ drop
fn extend_from_counter(values: &mut Vec<u32>, start: u32, count: usize) {
values.reserve(count);
let old_len = values.len();
let spare = values.spare_capacity_mut();
for (offset, slot) in spare.iter_mut().take(count).enumerate() {
slot.write(start + offset as u32);
}
// SAFETY: ลูปด้านบน initialize ครบ count ช่องที่ต่อจาก old_len
unsafe { values.set_len(old_len + count) };
}
#[test]
fn fills_only_initialized_slots() {
let mut values = vec![7];
extend_from_counter(&mut values, 10, 3);
assert_eq!(values, vec![7, 10, 11, 12]);
extend_from_counter(&mut values, 99, 0);
assert_eq!(values.len(), 4);
}
วาง panic boundary ก่อน unsafe
ตัวอย่างคำนวณค่าที่เขียนแบบไม่ล้มกลางลูป หาก producer อาจ panic ให้เพิ่ม length ทีละส่วนที่ยืนยันแล้ว หรือใช้ guard ซึ่งปรับ length ตอน unwind อย่าวาง set_len(old_len + count) ไว้ล่วงหน้า เพราะ destructor อาจอ่านช่องที่ยังไม่ได้ initialize
เริ่มจาก extend เมื่อ iterator ปกติพอ เพราะปลอดภัยและ optimizer ทำงานได้ดี ใช้ spare_capacity_mut เมื่อ profiler ชี้ว่าการเขียน buffer โดยตรงคุ้มกับ invariant เพิ่ม เหมือนโกดังที่ยอมเปิดประตูหลังเฉพาะทีมที่นับกล่องและเซ็นรับครบ
Recap
-
reserveก่อนขอ spare capacity - initialize จริงกี่ช่อง เพิ่ม length เท่านั้น
- อธิบาย
SAFETYด้วย invariant ไม่ใช่คำว่า “น่าจะปลอดภัย” - ออกแบบ panic/error path ก่อนใช้กับ producer จริง