Rust VecDeque::pop_front_if: หยิบหัวคิวเฉพาะเมื่อพร้อม
คิวงานมักมีกฎว่า “หยิบหัวคิวได้ต่อเมื่อถึงเวลา” ถ้าเขียน front() แล้วตามด้วย pop_front() เราต้องรักษาการยืมและเงื่อนไขสองจังหวะเองครับ VecDeque::pop_front_if ส่ง &mut T ของหัวคิวเข้า predicate และนำออกเฉพาะเมื่อได้ true
WHY: ตรวจบัตรตรงประตูเดียวกับที่ปล่อยคนออก
เหมือนเจ้าหน้าที่ดูตั๋วของคนหน้าสุดแล้วเปิดประตูเฉพาะตั๋วที่ถึงรอบ คนข้างหลังห้ามแซงและคิวเดิมไม่ถูกสแกนทั้งหมด API นี้เหมาะกับ priority ที่จัดไว้แล้ว, retry queue และ state machine ที่ตัดสินจากสมาชิกหัวสุด
use std::collections::VecDeque;
fn take_ready(queue: &mut VecDeque<(u64, &'static str)>, now: u64) -> Option<&'static str> {
queue
.pop_front_if(|(ready_at, _)| *ready_at <= now)
.map(|(_, job)| job)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn keeps_unready_head_in_place() {
let mut queue = VecDeque::from([(20, "later"), (10, "blocked-behind")]);
assert_eq!(take_ready(&mut queue, 15), None);
assert_eq!(queue.front(), Some(&(20, "later")));
assert_eq!(queue.len(), 2);
}
#[test]
fn removes_ready_head_once() {
let mut queue = VecDeque::from([(10, "ready"), (20, "later")]);
assert_eq!(take_ready(&mut queue, 15), Some("ready"));
assert_eq!(queue.front(), Some(&(20, "later")));
}
}
Predicate แก้ค่าได้ แม้สุดท้ายไม่ pop
เพราะ closure ได้ &mut T การแก้ค่าจะคงอยู่แม้คืน false เช่นเพิ่ม attempts แล้วตัดสินว่ายังไม่พร้อม พลังนี้มีประโยชน์แต่ควรใช้ให้เห็นชัด ถ้าต้องการเพียงอ่าน ให้ predicate ไม่ mutate เพื่อไม่ให้ reviewer ต้องตาม side effect ที่ซ่อนใน boolean
ฟังก์ชันนี้ไม่แก้ starvation หากงานหัวคิวติดถาวร สมาชิกด้านหลังจะยังถูกบัง ถ้าระบบต้องข้ามงานเสีย ควรกำหนด dead-letter, timeout หรือโครงสร้าง priority แยก อย่าวนเรียก pop_front_if แล้วหวังว่าคิวจะจัดตัวเอง
Recap
- ใช้เมื่อ policy ตรวจเฉพาะหัวคิวจริง ๆ
-
falseเก็บสมาชิกไว้ตำแหน่งเดิม - mutation ใน predicate คงอยู่แม้ไม่ pop
- ออกแบบ starvation และ dead-letter แยกจาก API นี้