今天就分享 3 個 Rust 記憶體招式,copy_from_slice
、split_at_mut
、chunks_exact_mut
。
copy_from_slice
手上兩塊等長的 slice,要把 A 複到 B,不用自己寫 for
迴圈。用標準庫已經幫你做過 bounds 檢查的 copy_from_slice
。
fn stamp_prefix(dst: &mut [u8], prefix: &[u8]) {
assert!(prefix.len() <= dst.len());
let (head, _) = dst.split_at_mut(prefix.len());
head.copy_from_slice(prefix);
}
長度不對會直接 panic 喔
fn overwrite(dst: &mut [u8], src: &[u8]) {
dst.copy_from_slice(src); // 需要等長,否則 panic
}
split_at_mut
Rust 不允許同一個切片同時有兩個 &mut
,但不重疊的兩段就沒問題。split_at_mut
幫你安全地把一塊切成兩塊。
fn fill_head_tail(buf: &mut [u8]) {
let n = buf.len() / 2;
let (head, tail) = buf.split_at_mut(n); // head 和 tail 互不重疊
// 同時操作兩塊
head.fill(0xAA);
tail.fill(0x55);
}
你想「邊讀 A、邊把結果寫到 B」,但 A 和 B 其實在同一塊大陣列裡不同區段,split_at_mut
就是安全首選。
chunks_exact_mut
很多資料其實是「固定欄位長度」:例如 16-byte 的 UUID、20-byte 的 header… 與其手寫索引,不如讓切片自己吐出一塊一塊的 view。
fn xor_each_block_16(buf: &mut [u8], key: [u8; 16]) {
for block in buf.chunks_exact_mut(16) {
for (b, k) in block.iter_mut().zip(&key) {
*b ^= *k;
}
}
// 若長度不是 16 的倍數,剩下的在 remainder 處理
let rem = buf.chunks_exact_mut(16).into_remainder();
for (b, k) in rem.iter_mut().zip(&key) {
*b ^= *k;
}
}
chunks_exact_mut(4)
讓你自然地以「一筆」為單位處理,不用手算索引、也不會越界。
Vec
的配置姿勢很多人會寫 Vec::with_capacity(len)
然後想「直接當作已填滿」使用,不行。安全作法用 resize
或建一個全零的:
fn new_zeroed(len: usize) -> Vec<u8> {
vec![0u8; len] // 配好 + 寫零(最安全)
// 或者:
// let mut v = Vec::with_capacity(len);
// v.resize(len, 0);
// v
}
set_len 是 unsafe,除非你真的保證之後每個位元組都會被正確寫入,否則不要用。
寫作業寫到兩眼一黑,為什麼作業這麼多啊?而且快考試了書還唸不完,我真的好爛:(