Rust array::from_fn: สร้าง array ของค่าที่ไม่ใช่ Copy ทีละช่อง
ต้องสร้าง [String; 4] จากค่าแต่ละช่อง แต่ syntax [value; 4] ใช้ไม่ได้เมื่อ String ไม่ใช่ Copy ครับ std::array::from_fn ให้ closure สร้างสมาชิกแต่ละตัวจาก index แล้วคืน array ขนาดคงที่ เหมือนช่างทำลิ้นชักสี่ช่องโดยวัดขนาดของแต่ละช่อง แทนการถ่ายสำเนาชิ้นเดียวสี่ครั้ง
ฟังก์ชันเดิน index จากศูนย์ไปหน้า array และเรียก closure ทีละครั้ง จึงสร้างค่า unique หรือใช้ mutable state ได้โดยตรง ขนาด array ต้องรู้จาก type context หรือกำหนดให้ชัด; หากขนาดเป็นศูนย์ closure ไม่ถูกเรียกเลย ตามเอกสาร official
#[cfg(test)]
mod tests {
#[test]
fn builds_non_copy_values_in_index_order() {
let labels: [String; 3] = std::array::from_fn(|i| format!("slot-{i}"));
assert_eq!(labels, ["slot-0", "slot-1", "slot-2"]);
}
#[test]
fn zero_length_does_not_call_builder() {
let empty: [String; 0] = std::array::from_fn(|_| panic!("must not run"));
assert!(empty.is_empty());
}
}
เมื่อไรควรใช้ array
array เหมาะเมื่อจำนวนช่องเป็นส่วนหนึ่งของสัญญา เช่น ช่องสถานะของ protocol ที่มีจำนวนคงที่ และอยากให้ compiler ตรวจขนาดให้ ถ้าจำนวนสมาชิกมาจาก config หรือ input ที่เปลี่ยนระหว่างรัน ใช้ Vec<T> จะตรงกว่า เพราะ N ใน [T; N] เป็น const generic ไม่ใช่ค่าที่อ่านตอน runtime
closure อาจมี side effect แต่ถ้าสร้างสมาชิกช่องกลางแล้วล้มเหลวด้วย panic สมาชิกที่สร้างก่อนหน้าจะถูก drop ตามกลไก Rust อย่าพึ่ง side effect ภายนอกว่าถูก rollback เอง เช่น เขียนไฟล์หรือส่ง network ต้องมีขอบเขต transaction แยก การสร้างค่าภายในหน่วยความจำอย่างตัวอย่างเข้าใจง่ายและปลอดจากปัญหานั้น
Recap
- ใช้
from_fnเมื่อสมาชิกไม่ใช่Copyหรือค่าแต่ละช่องต่างกัน - ใส่ type ของ array ให้ compiler รู้ขนาด
N - ทดสอบลำดับ index และกรณีขนาดศูนย์
- ใช้
Vecเมื่อขนาดต้องกำหนดตอน runtime