Avatar ·

Как повторить строку несколько раз в Rust? Пример с умножением строки на число

Привет, коллеги! Я только начал изучать Rust и столкнулся с неожиданной проблемой. В Python я привык писать что-то вроде `"hello" * 3`, чтобы получить `"hellohellohello"`. В Rust я попытался сделать то же самое: ```rust fn main() { let s = "hello" * 3; println!("{}", s); } ``` Но компилятор выдаёт ошибку: `cannot multiply `&str` by `{integer}``. Я понимаю, что Rust — строго типизированный язык, и умножение строк на числа не определено по умолчанию, но как тогда правильно повторить строку несколько раз? Я читал, что в Rust есть трейты и методы, но пока не разобрался. Мне нужно повторять строку динамически, например, для создания разделителя в выводе: `"---"` повторить 10 раз, чтобы получить строку из 30 дефисов. Также хотелось бы понять, как это сделать эффективно, без лишних аллокаций, если строка большая. Подскажите, пожалуйста, как правильно решить эту задачу в Rust? Есть ли встроенная функция или макрос для этого? Или нужно писать свою реализацию через цикл? Заранее спасибо за помощь! <<>>

Правильный способ повторения строки в Rust: метод repeat()

В Rust нет перегрузки оператора умножения для строк, как в Python. Вместо этого стандартная библиотека предоставляет метод repeat() для типа String и строковых срезов &str. Этот метод определён в трейте std::ops::Mul, но не для прямого умножения — он вызывается явно.

Вот как правильно повторить строку в Rust:

fn main() {
    let s = "hello".repeat(3);
    println!("{}", s); // выведет: hellohellohello

    // Для String тоже работает
    let base = String::from("abc");
    let repeated = base.repeat(5);
    println!("{}", repeated); // abcabcabcabcabc
}

Как это работает

Метод repeat(n):

  • Принимает usize (беззнаковое целое) — количество повторений
  • Возвращает новый String (аллоцирует память)
  • Работает как с &str, так и с String
  • Если n == 0, возвращает пустую строку

Пример с разделителем

fn main() {
    let separator = "-".repeat(30);
    println!("{}", separator); // ------------------------------

    // Динамическое количество
    let n = 10;
    let line = "=".repeat(n);
    println!("{}", line); // ==========
}

Эффективность

Метод repeat() реализован эффективно:

  • Он заранее вычисляет необходимый размер буфера: len * n
  • Выделяет память ровно один раз
  • Заполняет строку в цикле (часто с оптимизацией копирования блоков)

Сравните с ручным циклом:

// Плохо: много аллокаций
fn bad_repeat(s: &str, n: usize) -> String {
    let mut result = String::new();
    for _ in 0..n {
        result.push_str(s); // может переаллоцироваться на каждой итерации!
    }
    result
}

// Хорошо: предварительно резервируем память
fn good_repeat(s: &str, n: usize) -> String {
    let mut result = String::with_capacity(s.len() * n);
    for _ in 0..n {
        result.push_str(s);
    }
    result
}

// Лучше всего: используем repeat()
fn best_repeat(s: &str, n: usize) -> String {
    s.repeat(n) // всё делает за нас
}

Что делать, если нужно повторить символ?

Для одного символа есть ещё более простой способ — использовать std::iter::repeat():

use std::iter;

fn main() {
    let stars: String = iter::repeat('*').take(10).collect();
    println!("{}", stars); // **********
}

Но для строк repeat() — самый идиоматичный и производительный вариант.

Важное замечание

Метод repeat() доступен начиная с Rust 1.16 (для String) и с Rust 1.40 (для &str). Убедитесь, что ваша версия Rust не слишком старая. Проверить можно командой rustc --version.

<<>>

Альтернативный подход: макрос format! с повторением

Если вам нужно повторить строку только один раз и вы не хотите вызывать метод repeat(), можно использовать макрос format! в сочетании с итератором:

fn main() {
    let s = format!("{}{}{}", "ha", "ha", "ha");
    println!("{}", s); // hahaha
}

Но это не масштабируется. Для динамического количества повторений лучше использовать std::iter::repeat() с take():

use std::iter;

fn main() {
    let n = 5;
    let repeated: String = iter::repeat("yo").take(n).collect();
    println!("{}", repeated); // yoyoyoyoyo
}

Когда это может быть полезно

  • Если нужно повторить не строку, а более сложное выражение
  • Если хотите вставить повторение прямо в макрос format!:
let count = 3;
let result = format!("[{}]", ".".repeat(count));
// или
let result = format!("[{}]", iter::repeat(".").take(count).collect::());

Однако метод repeat() всё равно остаётся предпочтительным из-за читаемости и производительности. Итераторный подход даёт больше гибкости, но для простого повторения строки он избыточен.