Shanraq.org Shanraq.org
String и &str: хранить или читать
IT

Rust: с нуля до своего органайзера Урок 22 из 35

String и &str: хранить или читать

Урок 22. Выбрать владеющую строку для хранения и текстовое представление для чтения.

Текст переведён с помощью ИИ.

Предварительно: уроки 9 и 18–21. Если перемещение String неясно, повторите урок 19.

Образ и опорная карта

Собственная записная книжка хранит ваши записи; открытая на нужной странице книжка даёт прочитать запись, но сама открытая страница не становится второй книжкой. String владеет текстом и может увеличиваться при разрешённом изменении. &str — представление существующего текста для чтения: ссылка на непрерывный фрагмент текста с известной длиной, но без владения его хранилищем. Образ ограничен: текстовый литерал тоже имеет тип &str, хотя его данные находятся в программе и не обязаны принадлежать переменной String.

Хранить и менять → String; принять для чтения → &str; владелец остаётся жив → представление пригодно. Вспомните эту карту без страницы. "Отдых" — литерал &str; String::from("Чтение") создаёт отдельную владеющую строку. Метод .as_str() даёт &str для чтения всего текста String, не копируя его. Точка вызывает метод, как .len() в уроке 15.

Один параметр для двух источников текста

В organizer сохраните прежний src/main.rs, полностью замените его следующим кодом и выполните cargo run в папке с Cargo.toml. Другие файлы и зависимости не меняются. Предскажите три строки; ниже показан только вывод программы.

До запуска прочитайте вызовы: show_title(owned.as_str()) передаёт представление текста из владельца, а show_title(literal) — уже готовый литерал &str. Параметр title: &str в обоих случаях получает текст для чтения, не забирая String.

fn show_title(title: &str) {
    println!("Название: {title}");
}

fn main() {
    let owned = String::from("Чтение");
    let literal: &str = "Отдых";
    show_title(owned.as_str());
    show_title(literal);
    println!("Хранится: {owned}");
}
Название: Чтение
Название: Отдых
Хранится: Чтение

owned можно снова использовать: функция не получила владение. Литерал записан прямо в исходнике и доступен на протяжении работы программы. Представление, полученное через owned.as_str(), не должно использоваться после исчезновения owned; компилятор не позволит сохранить висячую ссылку.

Что выбирать в функции

Если функция только читает название, &str обычно принимает больше источников текста, чем &String: литералы, целые String через .as_str() и части строк, которые изучим в уроке 23. Это не означает, что &str сам умеет хранить новую изменяемую запись. Если органайзер должен владеть названием после окончания вызова, ему потребуется собственный String; способ передачи и хранения разберём, когда появится тип задачи.

Нельзя вызвать push_str через &str: это представление для чтения. Отдельный неверный пример даёт E0599 — такого метода у этого типа нет:

fn main() {
    let owned = String::from("План");
    let view = owned.as_str();
    view.push_str("!");
}

Чтобы менять исходную строку, нужен владелец let mut owned и подходящий изменяемый доступ из урока 21. Изменение не делают через старое представление для чтения: оно могло бы стать недействительным после роста строки. &str будет встречаться и как часть текста, а не только как весь текст.

Проверка понимания

  1. Кто владеет байтами после let owned = String::from("Чтение")?
  2. Что возвращает owned.as_str() — копию или представление?
  3. Почему show_title(literal) не требует String::from?

Проверьте: owned; представление без копирования текста; литерал уже имеет тип &str. Если выбор типа пока неясен, попробуйте объяснить его через образ книжки и границу этого образа.

Задание

Обязательное. Напишите show_task(title: &str, minutes: u32). В main создайте владеющую строку Чтение и литерал Отдых; вызовите функцию с owned.as_str(), 15 и literal, 5. Выведите затем Сохранено: Чтение. Ожидаются три строки в этом порядке. Не создавайте копию владеющей строки ради печати.

Свои данные. Замените название и минуты, сохранив один вызов для String и один для литерала.

Подсказка

Внутри функции: println!("{title}: {minutes} мин");. У первого вызова нужен .as_str(), у второго — нет. owned остаётся у main.

Эталон после попытки

fn show_task(title: &str, minutes: u32) {
    println!("{title}: {minutes} мин");
}

fn main() {
    let owned = String::from("Чтение");
    let literal: &str = "Отдых";
    show_task(owned.as_str(), 15);
    show_task(literal, 5);
    println!("Сохранено: {owned}");
}
Чтение: 15 мин
Отдых: 5 мин
Сохранено: Чтение

Функция принимает оба источника текста для чтения, а main сохраняет владение строкой. Официальный разбор строк.

Предыдущий урок · Оглавление · Следующий урок

Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом

Комментарии (0)

Пока нет комментариев. Будьте первым.