Skip to content

String::insert

String methods · Strings

Level: reference · for working programmers

One line: Inserts one char at a byte offset, shifting everything after it — O(n), and it panics off a character boundary.

pub fn insert(&mut self, idx: usize, ch: char)

Stable since 1.0.0.

The index is a byte offset, with the same two panics as slicing: out of range, or inside a character. s.insert(0, c) is always legal; s.insert(s.len(), c) is push.

Everything after the offset moves, so inserting at the front of a long string in a loop is quadratic. Building in order and using push_str, or collecting an iterator, is almost always better.

The argument is a char; insert_str takes text.

A very common misuse is treating the index as a character position. On non-ASCII text it is not, and the offset has to come from char_indices.

Example

string_insert.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");
    s.insert(0, '>');
    s.insert(3, '-');
    println!("{s:?}");

    // At the end, it is push.
    let n = s.len();
    s.insert(n, '!');
    println!("{s:?}");

    // Byte offsets, not character positions.
    let mut accented = String::from("héllo");
    println!("boundary at 2? {}", accented.is_char_boundary(2));
    let third = accented.char_indices().nth(2).unwrap().0;
    accented.insert(third, '-');
    println!("{accented:?}");

    // Everything after the offset shifts, so this is O(n).
    let mut reversed = String::new();
    for c in "abcd".chars() {
        reversed.insert(0, c);
    }
    println!("{reversed:?}");

    // The linear way to do the same thing.
    println!("{:?}", "abcd".chars().rev().collect::<String>());
}

Verified output of string_insert.rs — regenerated by tools/run_examples.py, never hand-typed.

">he-llo"
">he-llo!"
boundary at 2? false
"hé-llo"
"dcba"
"dcba"

See also

String::insert in the standard library ↗

Po polsku

Indeks jest przesunięciem w bajtach, a nie numerem litery, i polszczyzna demaskuje to od razu: "żółw" ma cztery znaki, ale siedem bajtów, bo każda litera z diakrytykiem zajmuje dwa. Stąd najczęstsze nadużycie tej metody — s.insert(2, '-') w intencji „po drugiej literze” potrafi trafić w środek znaku i program panikuje; na stronie widać to jako boundary at 2? false dla "héllo", a poprawne przesunięcie bierze się z char_indices(). Druga sprawa to koszt: wszystko za miejscem wstawienia przesuwa się, więc insert(0, c) w pętli jest kwadratowe — przykład pokazuje obok tańszy zapis "abcd".chars().rev().collect::<String>(), który daje ten sam wynik "dcba" w jednym przebiegu. Na samym końcu łańcucha znaków insert to zwykły push, a do wstawiania całego tekstu zamiast pojedynczego char służy insert_str.

Szukaj po polsku: przesunięcie w bajtach · polskie znaki diakrytyczne w Ruscie · panika na granicy znaku · rust String::insert · rust char_indices byte offset