String::as_mut_vec¶
Level: reference · for working programmers
One line: The underlying Vec<u8>, mutably — unsafe, because you can resize it and must leave valid UTF-8 behind.
Stable since 1.0.0. unsafe — the caller carries the invariant described below. Usable in a const context.
This is the most powerful and most dangerous view of a String. Unlike as_mut_str, the Vec can grow, shrink and be written arbitrarily — and the String is required to hold valid UTF-8 when the borrow ends.
The contract is exactly that: valid UTF-8 by the time the &mut Vec<u8> is dropped. In between, anything goes.
Almost every real use has a safe equivalent — push_str, retain, truncate, replace_range. The honest cases are decoding into a buffer whose validity you establish yourself, and byte-level work that would otherwise need a copy out and back.
Breaking the invariant is undefined behaviour, not mojibake.
Example¶
string_as_mut_vec.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.
fn main() {
let mut s = String::from("hello");
// Sound: ASCII appended to ASCII is still valid UTF-8.
unsafe { s.as_mut_vec().extend_from_slice(b" world") }
println!("{s:?}");
// Sound: truncating at a boundary we checked.
let mut wide = String::from("héllo");
let cut = wide.floor_char_boundary(3);
unsafe { wide.as_mut_vec().truncate(cut) }
println!("{wide:?}");
// The safe equivalents of both.
let mut safe = String::from("hello");
safe.push_str(" world");
safe.truncate(5);
println!("{safe:?}");
// Why the truncate above needed a boundary check.
let check = "héllo";
println!("boundary at 2? {} at 3? {}",
check.is_char_boundary(2), check.is_char_boundary(3));
}
Verified output of string_as_mut_vec.rs — regenerated by tools/run_examples.py, never hand-typed.
See also¶
String::as_bytes— the read-only version, which is safeString::as_mut_str— the safe mutable view, length-preservingString::into_bytes— taking theVecby value insteadstr::as_bytes_mut— the same idea on a&mut str
String::as_mut_vec in the standard library ↗
Po polsku¶
To najpotężniejszy i najniebezpieczniejszy widok na String: w odróżnieniu od as_mut_str ten Vec<u8> wolno powiększać, skracać i zapisywać zupełnie dowolnie, a umowa jest jedna — poprawny UTF-8 w chwili, gdy pożyczenie się kończy; po drodze może być cokolwiek. Warto to powiedzieć wprost, bo polska intuicja podpowiada tu coś zupełnie innego: złamanie tego niezmiennika nie kończy się „krzaczkami” na ekranie, jak przy pomyleniu Latin-2 z Windows-1250, tylko niezdefiniowanym zachowaniem (undefined behaviour) — kod czytający później ten String ma prawo założyć, że bajty są poprawne, i optymalizować się pod to założenie. Dlatego skracanie w przykładzie poprzedza floor_char_boundary(3): cięcie na bajcie 2 przepołowiłoby é, co potwierdza ostatni wiersz wyniku — boundary at 2? false at 3? true. Prawie każde realne zastosowanie ma bezpieczny odpowiednik (push_str, retain, truncate, replace_range), więc unsafe zostaw na dekodowanie do własnego bufora i na pracę bajtową, która inaczej wymagałaby kopii tam i z powrotem.
Szukaj po polsku: niezdefiniowane zachowanie w Ruscie · krzaczki a niepoprawny UTF-8 · rust as_mut_vec safety invariant · rust unsafe String valid utf8