Skip to content

String::as_mut_vec

String methods · Strings

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.

pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8>

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.

"hello world"
"hé"
"hello"
boundary at 2? false  at 3? true

See also

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