Rust и безопасное системное ПО
Все объяснения, задачи и лабораторная в одном месте.
Можно сохранить страницу в PDF через печать браузера. Для печати разборы ответов раскрываются автоматически.
1. Ownership, borrowing и перемещение
Объяснение
У значения один владелец. Заимствование допускает либо несколько неизменяемых ссылок, либо одну изменяемую в пересекающейся области использования. Это предотвращает множество ошибок памяти на этапе компиляции.
Задача для самостоятельного решения
Почему нельзя менять vector через push, удерживая используемую ссылку на элемент?
Показать разбор ответа
push может перераспределить память и сделать ссылку висячей. Компилятор запрещает конфликтующее заимствование; завершите использование ссылки до изменения контейнера.
2. Enums, pattern matching и Result
Объяснение
Enum описывает набор альтернатив. Option выражает отсутствие значения, Result — успех или ошибку. Оператор ? возвращает ошибку вызывающему коду, а unwrap вызывает panic при отсутствии ожидаемого варианта.
Задача для самостоятельного решения
Что использовать для неверного пользовательского ввода: unwrap или Result?
Показать разбор ответа
Result: это ожидаемый отказ, который нужно показать пользователю. Panic уместен для нарушенного внутреннего инварианта, а не обычной ошибки формы.
3. Traits, generics и lifetimes
Объяснение
Trait задаёт поведение, generics позволяют обобщать алгоритмы. Lifetime описывает отношение сроков жизни ссылок и не продлевает жизнь объекта. Аннотация помогает проверить, что ссылка не переживает данные.
Задача для самостоятельного решения
Может ли функция вернуть ссылку на локальный String?
Показать разбор ответа
Нет: String уничтожается при выходе. Верните String с передачей владения или ссылку на данные вызывающего кода с подходящим lifetime.
4. Коллекции, iterators и zero-cost abstractions
Объяснение
Итераторы вычисляют элементы по запросу. map без потребляющей операции не выполняет всю обработку. Заимствующий iterator и into_iter имеют разные последствия для владения коллекцией.
Задача для самостоятельного решения
Как получить удвоенные числа из [1,2,3]?
Показать разбор ответа
Преобразовать iterator через map и собрать collect: результат [2,4,6]. Уточните, нужны ли ссылки на исходные значения или передача владения элементами.
5. Async, Send/Sync и конкурентность
Объяснение
Future продвигается executor при опросе. Send позволяет перенос между потоками, Sync — совместное использование через ссылки при соблюдении типов. Блокирующая работа внутри async-задачи может остановить executor.
Задача для самостоятельного решения
Почему обычное долгое чтение блокирующего сокета мешает async-сервису?
Показать разбор ответа
Оно удерживает поток executor. Используйте неблокирующее API runtime или вынесите блокирующую работу в предназначенный пул с ограниченной конкуренцией.
6. Unsafe, FFI, тесты и профилирование
Объяснение
Unsafe разрешает операции, корректность которых автор обязан доказать вручную. Он не отключает все проверки языка. FFI требует согласовать layout, ABI, владение и способ освобождения памяти.
Задача для самостоятельного решения
Кто освобождает буфер, выделенный C-библиотекой?
Показать разбор ответа
Тот, кто указан её контрактом, обычно через её же функцию освобождения. Произвольный Rust allocator может быть несовместим; обёртка должна выразить владение и Drop.
Лабораторная работа
Подготовка
Rust toolchain. Сохраните main.rs, выполните rustc main.rs и ./main.
Учебный пример
fn total(values: &[i32]) -> i32 {
values.iter().sum()
}
fn main() {
let values = vec![1,2,3];
assert_eq!(total(&values), 6);
println!("{}", values.len());
}Как работает пример и что ожидать
Вывод 3. Функция получает заимствованный slice и не забирает владение vector. Поэтому values остаётся доступен после вызова. При передаче самого Vec по значению нужно было бы явно вернуть владение или больше не использовать прежнюю переменную.
Итоговая работа
Сделайте CLI с Result вместо panic для неверного ввода, тестами и разделением I/O от логики. Добавьте обработку нескольких файлов с ограничением конкуренции и объясните Send/Sync используемых типов.
Проверка результата
1. Опишите исходные данные и условия запуска, чтобы другой человек мог повторить работу.
2. Приложите результат обычного сценария и сравните его с ожидаемым.
3. Проверьте неверный вход, граничный случай и отказ зависимости, если она есть.
4. Объясните выбранное решение и известное ограничение.
5. Сохраните исправления после самопроверки вместе с примером, который раньше не работал.
Как оценить работу
По каждому пункту поставьте 0 (не выполнено), 1 (выполнено с пробелами) или 2 (результат воспроизводим и объяснён). Если обязательный сценарий не работает, вернитесь к нему независимо от общей суммы. Это рубрика самопроверки: сайт не исполняет присланный код и не выдаёт автоматическую оценку проекта.