Введение
Перемещение String передаёт владение, но многим функциям нужен только временный доступ. В Rust такой временный доступ называется заимствованием и представляется ссылкой.
Вы завершите подготовленную программу со списком гостей в три небольших этапа: сначала просмотрите принадлежащий программе текст через общую ссылку, затем намеренно убедитесь, почему общий доступ не позволяет изменять данные, а после этого выполните одно контролируемое изменение через изменяемую ссылку. Итоговый вывод докажет, что main по-прежнему владеет списком и может использовать его.
Просмотр данных через общую ссылку
На этом шаге вы предоставите функции доступ к String только для чтения, вместо того чтобы передавать ей владение.
Перейдите в подготовленный проект Cargo и откройте его исходный файл:
cd /home/labex/project/guest-borrowing
nano src/main.rs
Подготовка создала полный проект и оставила один заполнитель в вызове inspect_guests. Тип его параметра — &String. Символ & означает «ссылка на String»: функция может временно просматривать значение, но не становится его владельцем.
Замените только /* Step 1: borrow guest_list */ на &guest_list, чтобы вызов выглядел так:
inspect_guests(&guest_list);
Здесь &guest_list создаёт общую ссылку. Общая ссылка предоставляет доступ только для чтения, которым можно делиться, не передавая владение самой String.
Сохраните файл с помощью Ctrl+O, нажмите Enter, затем выйдите с помощью Ctrl+X. Запустите программу:
cargo run --quiet
Вывод должен быть таким:
Inspecting: Ari, Bo
Caller still owns: Ari, Bo
Before update: Ari, Bo
Updated: Ari, Bo
Первая строка выводится через заимствованную ссылку. Вторая строка подтверждает сохранение владения: после возврата из inspect_guests функция main по-прежнему может использовать guest_list. Функция обновления также читает текущее значение, но пока не изменяет его.
Наблюдение за ограничением общей ссылки
На этом шаге вы намеренно попытаетесь изменить String через общую ссылку. Ожидаемая ошибка проверки компилятора покажет правило заимствования Rust.
Снова откройте исходный файл:
nano src/main.rs
Внутри add_guest удалите только начальные // из подготовленной строки, чтобы она стала такой:
list.push_str(", Mina");
Метод push_str добавляет текст в String, поэтому ему требуется разрешение на изменение значения. Однако list сейчас имеет тип &String, который предоставляет общий доступ только для чтения.
Сохраните файл и выйдите из редактора. Перед проверкой предскажите результат: компилятор должен отклонить попытку изменения, потому что общая ссылка не может предоставить изменяемый доступ.
Запустите проверку. Ошибка ожидаема:
cargo check
Найдите в диагностике следующие неизменные части:
error[E0596]: cannot borrow `*list` as mutable, as it is behind a `&` reference
...
consider changing this to be a mutable reference
Формулировка *list обозначает объект String, доступный через ссылку. Rust не утверждает, что String вообще нельзя изменять. Сообщение означает, что именно эта ссылка &String не предоставляет разрешения на изменение. На следующем шаге вы предоставите контролируемый изменяемый доступ.
Изменение данных через изменяемую ссылку
На этом шаге вы предоставите add_guest временное исключительное разрешение изменять String вызывающего кода.
Изменяемая ссылка имеет форму &mut T. Полезное правило для начинающих: много читателей или один писатель одновременно. Общие ссылки разрешают чтение, а одна изменяемая ссылка предоставляет временный исключительный доступ для записи. Такая исключительность не позволяет двум частям программы неожиданно изменять одно и то же значение.
Откройте файл:
nano src/main.rs
Выполните три точечных изменения:
- Измените параметр
add_guestс&Stringна&mut String. - Добавьте
mutв объявление, чтобы оно выглядело какlet mut guest_list = .... - Измените вызов
add_guestс&guest_listна&mut guest_list.
Завершённые сигнатура функции и вызов должны иметь следующий вид:
fn add_guest(list: &mut String) {
add_guest(&mut guest_list);
Два использования mut связаны между собой, но выполняют разные задачи. let mut guest_list указывает, что принадлежащее программе значение можно изменять. Затем &mut guest_list создаёт одну временную изменяемую ссылку и предоставляет add_guest исключительный доступ для записи на время вызова.
Сохраните файл и выйдите из редактора, затем проверьте исправление:
cargo check
Результат Finished без ошибки E0596 означает, что разрешения теперь согласованы. Запустите программу:
cargo run --quiet
Итоговый вывод должен быть таким:
Inspecting: Ari, Bo
Caller still owns: Ari, Bo
Before update: Ari, Bo
Updated: Ari, Bo, Mina
Изменяемое заимствование завершается после возврата из add_guest. Последний вывод снова может прочитать guest_list, что доказывает: владение осталось в main, а функция выполнила контролируемое изменение.
Итоги
Вы использовали &String для общего доступа только для чтения и &mut String для временного исключительного изменения. В обоих случаях вызывающий код сохранил владение, а компилятор помог обеспечить различие между просмотром и изменением заимствованных данных.



