ปูสีส้มแดงต้นฉบับกำลังวางลูกบอลลงช่องว่างท้ายรางหน่วยความจำบนโต๊ะสีมิ้นต์

Rust Vec::spare_capacity_mut: เติม buffer ที่จองไว้โดยไม่สร้าง Vec ชั่วคราว

พี่โชว์Engineering

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 จริง