Rust Vec::retain_mut: แก้ค่าและกรองสมาชิกในรอบเดียวโดยรักษาลำดับ
ถ้าต้อง normalize ค่าทุกตัวแล้วคัดของเสียออก เรามักเขียน iter_mut() รอบหนึ่งและ retain() อีกรอบครับ Vec::retain_mut ส่ง &mut T เข้า predicate จึงแก้ค่าสมาชิกก่อนตัดสินใจเก็บได้ในรอบเดียว และรักษาลำดับของตัวที่เหลือ
fn normalize_positive(values: &mut Vec<i32>) {
values.retain_mut(|value| {
*value *= 2;
*value > 0
});
}
fn main() {
let mut values = vec![-2, 1, 3, 0];
normalize_positive(&mut values);
assert_eq!(values, vec![2, 6]);
println!("retain_mut checks passed");
}
Closure ถูกเรียกตามลำดับเดิมหนึ่งครั้งต่อสมาชิก การคืน true คือเก็บค่าที่อาจถูกแก้แล้ว ส่วน false คือทิ้ง เหมือนช่างหยิบสินค้าบนสายพาน ปรับฉลาก แล้วตัดสินใจวางกลับหรือใส่กล่อง reject ในมือเดียว
ข้อแลกเปลี่ยน
วิธีนี้ใช้พื้นที่เพิ่ม O(1) แต่การลบสมาชิกจำนวนมากจาก vector ต้องย้ายสมาชิกที่รอดให้ชิดกัน ต้นทุนรวมยังเป็น O(n) หากต้องสร้างผลลัพธ์ชนิดใหม่หรือเก็บค่าที่ถูกคัดออก ให้ใช้ drain, partition หรือ iterator ที่ collect แล้วสื่อ intent ได้ดีกว่า
อย่าใส่ side effect ที่ย้อนกลับไม่ได้ใน predicate เพราะหาก closure panic vector จะยังอยู่ในสถานะที่ปลอดภัยตามชนิด แต่ข้อมูลบางตัวอาจถูกแก้และบางตัวอาจถูกลบแล้ว การทำ normalization ควรเป็น deterministic และทดสอบ input ว่าง, ทุกตัวถูกลบ และทุกตัวผ่าน
Recap
- ใช้
retain_mutเมื่อแก้และกรองVecเดิมจริง ๆ - คืน
trueเพื่อเก็บค่าหลังแก้ - ใช้ทางเลือกอื่นเมื่อต้องเก็บของที่ถูกตัดหรือเปลี่ยนชนิดผลลัพธ์
- หลีกเลี่ยง side effect ภายนอกใน predicate