Zig std.mem.reverse: กลับลำดับในที่เดิม พร้อมเข้าใจ slice และ mutation
การกลับลำดับข้อมูลดูเหมือนโจทย์ง่าย แต่ช่วยเห็นหัวใจของ Zig ชัดมาก: slice เป็นมุมมองเหนือหน่วยความจำ และฟังก์ชันที่รับ mutable slice สามารถแก้ buffer ต้นฉบับได้ std.mem.reverse สลับสมาชิกหัว–ท้ายเข้าหากัน ใช้เวลา O(n) และพื้นที่เพิ่ม O(1)
เหมือนพลิกคิวบัตรบนโต๊ะโดยสลับใบซ้ายสุดกับขวาสุด ไม่ได้ถ่ายสำเนาไปโต๊ะใหม่ จึงเร็วและประหยัด แต่คนอื่นที่ถือมุมมองมายังโต๊ะเดิมจะเห็นลำดับใหม่ด้วย
const std = @import("std");
test "reverse an entire mutable slice" {
var values = [_]u8{ 1, 2, 3, 4, 5 };
std.mem.reverse(u8, values[0..]);
try std.testing.expectEqualSlices(u8, &.{ 5, 4, 3, 2, 1 }, values[0..]);
}
test "reverse only the selected window" {
var values = [_]u8{ 10, 20, 30, 40, 50 };
std.mem.reverse(u8, values[1..4]);
try std.testing.expectEqualSlices(u8, &.{ 10, 40, 30, 20, 50 }, values[0..]);
}
ตัวอย่างที่สองย้ำว่า slice กำหนดขอบเขตการแก้ได้ เรากลับเฉพาะ index 1 ถึงก่อน 4 สมาชิกหัวและท้ายจึงไม่เปลี่ยน Empty slice และสมาชิกเดียวก็ใช้ได้โดยไม่มีงานต้องทำ
ถ้าข้อมูลต้นทางต้องคงเดิม ให้จัด buffer ปลายทาง คัดลอกด้วย @memcpy แล้วค่อย reverse สำเนา การทำให้ mutation ปรากฏในชื่อฟังก์ชันหรือ API ช่วยป้องกันบั๊กที่ caller ไม่รู้ว่า array ของตัวเองถูกเปลี่ยน
Recap
- ส่ง mutable slice ที่ต้องการกลับจริง ๆ
- ใช้ subslice เพื่อจำกัดช่วงอย่างชัดเจน
- copy ก่อนเมื่อ caller ยังต้องใช้ลำดับเดิม
- ทดสอบทั้งจำนวนคู่ คี่ ว่าง และหนึ่งสมาชิกตามบริบท