Rust: с нуля до своего органайзера Урок 20 из 20
Заимствование для чтения
Урок 20. Передать строку функции для чтения и сохранить право использовать её после вызова.
Текст переведён с помощью ИИ.
Предварительно: уроки 1–19. Если перемещение неясно, повторите урок 19. Изменяемое заимствование будет в уроке 21.
Образ и опорная карта
Когда читателю нужна книга, необязательно отдавать её навсегда или делать вторую копию. Заимствование даёт временный доступ к значению без передачи владения. Образ ограничен: Rust проверяет сроки использования ссылок и правила доступа статически, а книжная аналогия не показывает всех этих проверок.
Владелец → & → ссылка для чтения → функция → владелец продолжает работу. Восстановите карту, закрыв страницу. Символ & перед значением создаёт ссылку; &String в типе означает ссылку на String для чтения. Сама ссылка не владеет строковым буфером.
Читаем без передачи владения
В проекте organizer из урока 6 сохраните прежний src/main.rs, замените его целиком кодом ниже и в папке с Cargo.toml выполните cargo run. Другие файлы и зависимости не меняются. Блок результата — только вывод программы.
fn show_title(title: &String) {
println!("В функции: {title}");
}
fn main() {
let title = String::from("Чтение");
show_title(&title);
println!("После вызова: {title}");
}
В функции: Чтение
После вызова: Чтение
show_title(&title) создаёт ссылку на строку и передаёт её функции. Параметр title: &String позволяет читать значение, но не менять его. Владелец в main сохраняет строку и может использовать её после вызова. Это и есть неизменяемое заимствование. Не путайте &title в вызове, которое создаёт ссылку, с &String в объявлении типа, которое описывает ожидаемый вид аргумента.
Граница доступа
Попытка менять строку через &String отклоняется с E0596:
fn change(title: &String) {
title.push_str("!");
}
fn main() {
let title = String::from("Чтение");
change(&title);
}
Ссылка для чтения может сосуществовать с другими ссылками для чтения. В то время как такой заимствованный доступ ещё используется, нельзя менять значение способом, который нарушил бы его. Точный конец заимствования компилятор определяет по последнему использованию ссылки, а не обязательно по ближайшей закрывающей скобке. Проверим это на отдельном примере:
fn main() {
let mut title = String::from("План");
let view = &title;
println!("До: {view}");
title.push_str("!");
println!("После: {title}");
}
До: План
После: План!
Последнее использование view находится до изменения, поэтому этот код допустим. Если попытаться снова использовать view после изменения, компилятор отклонит программу. Связь ссылки с владельцем и случаи возврата ссылок подробно изучим в уроках 23 и 47.
Проверка понимания
Почему первый пример сохраняет право печатать title в main, а пример с передачей String из урока 19 — нет? Может ли &String вызвать push_str? Ответы: ссылка не переносит владение; нет, для изменения нужен другой вид доступа.
Задание
Обязательное. Напишите show_task(title: &String, minutes: u32), которая выводит Чтение — 15 мин. В main создайте строку Чтение, вызовите функцию дважды с 15 и 20, затем выведите Название осталось: Чтение. Сначала предскажите три строки. Не применяйте clone() и не передавайте String по значению. Если функция не видит строку, проверьте наличие & и в типе параметра, и в вызове.
Подсказка
Число u32 передаётся по значению благодаря Copy; строку передайте как &title. В функции используйте println!("{title} — {minutes} мин");.
Эталон после попытки
fn show_task(title: &String, minutes: u32) {
println!("{title} — {minutes} мин");
}
fn main() {
let title = String::from("Чтение");
show_task(&title, 15);
show_task(&title, 20);
println!("Название осталось: {title}");
}
Чтение — 15 мин
Чтение — 20 мин
Название осталось: Чтение
Возьмите паузу и воспроизведите схему без подсказки: владелец сохраняется, функция получает временный доступ. Официальный разбор ссылок.
Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом
Комментарии (0)
Войдите, чтобы оставить комментарий →
Пока нет комментариев. Будьте первым.