ปูสีส้มแดงต้นฉบับกำลังจัดก้อนกรวดเป็นถาดละสามก้อนและแยกเศษที่เหลือไว้ข้างถาด

Rust slice::as_chunks: แบ่ง slice เป็นกลุ่มขนาดคงที่โดยไม่ copy

พี่โชว์Engineering

งานที่ประมวลข้อมูลทีละ N ค่า เช่น RGB, พิกัด หรือ block protocol มักเริ่มจาก chunks_exact แล้วแปลง slice ย่อยเป็น array เองครับ ตั้งแต่ Rust 1.88 slice::as_chunks::<N>() คืน (&[[T; N]], &[T]) ทำให้ compiler รู้ขนาดแต่ละกลุ่มและยังไม่ copy ข้อมูล

WHY: ถาดขนาดตายตัวกับเศษที่วางข้าง ๆ

ลองแบ่งขนมลงถาดละสามชิ้น ถาดเต็มทุกใบมีรูปทรงเดียวกัน จึงส่งต่อให้ฟังก์ชันที่รับ [T; 3] ได้ทันที ส่วนที่ไม่ครบถาดถูกคืนเป็น remainder แทนการหายเงียบ ๆ ช่วยให้เราเลือกว่าจะ reject, pad หรือเก็บไว้รอข้อมูลรอบถัดไป

fn rgb_luma(bytes: &[u8]) -> (Vec<u16>, &[u8]) {
    let (pixels, remainder) = bytes.as_chunks::<3>();
    let luma = pixels
        .iter()
        .map(|[r, g, b]| u16::from(*r) + u16::from(*g) + u16::from(*b))
        .collect();
    (luma, remainder)
}

#[test]
fn groups_without_copying() {
    let input = [10, 20, 30, 1, 2, 3, 99];
    let (luma, rest) = rgb_luma(&input);
    assert_eq!(luma, vec![60, 6]);
    assert_eq!(rest, &[99]);
}

#[test]
fn short_input_becomes_remainder() {
    let (luma, rest) = rgb_luma(&[1, 2]);
    assert!(luma.is_empty());
    assert_eq!(rest, &[1, 2]);
}

Const generic ทำให้ขอบเขตชัด

N เป็น const generic จึงรู้ตอน compile ว่าแต่ละ chunk ยาวเท่าไร แต่ N = 0 จะ panic ตอนเรียก ไม่ใช่ผลลัพธ์ว่าง หากขนาดมาจากผู้ใช้ต้อง validate ก่อนและอาจใช้ chunks_exact(runtime_size) แทน

ทั้ง chunks และ remainder borrow จาก input ห้ามเก็บนานกว่าต้นฉบับ และ as_chunks_mut เปิดให้แก้ backing slice เดิม จึงต้องระวัง alias ตามกติกา borrow ของ Rust

Recap

  • ใช้ as_chunks::<N> เมื่อขนาดกลุ่มรู้ตอน compile
  • จัดการ remainder อย่างตั้งใจ
  • ห้ามใช้ N = 0
  • จำว่าเป็น view แบบยืมข้อมูล ไม่ใช่การ copy