💡 Инструкция: Выберите один ответ из пяти. На 25 вопросов отведено 70 минут. В каждом вопросе верен только один вариант. После завершения вы увидите общий результат, результаты по 5 тематическим шкалам и подробные объяснения.
Вопрос 1 из 25
Какая реализация выражает механизм «Ленивость» без лишнего копирования?
Rust Rust · Ленивость Копировать
let mut calls = 0;
let iter = [1, 2, 3].iter().map(|n| { calls += 1; n * 2 });
println!("{calls}");
drop(iter);
Клонировать захваченное состояние перед каждым вызовом `calls`, не уточняя требуемый трейт вызова или время жизни.
Собирать каждый промежуточный итератор в Vec, чтобы ленивость не влияла на порядок. Сигнатура при этом почти не меняется, однако исходное предусловие остаётся скрытым.
Продублировать реализацию для каждого известного типа вокруг `calls`, вместо того чтобы исправить границы обобщения «Ленивость».
Добавить потребляющую операцию, если вычисление должно произойти; если нужны только побочные эффекты, явный for обычно читается честнее, чем map.
Заменить текущую форму `calls` на `Box<dyn Trait>` во всех местах, не проверяя владение, объектобезопасность и стоимость вызова.
Вопрос 4 из 25
Что проверяет `Vec::new`, если не расширять вывод за пределы выполненного пути?
Rust Rust · Ленивость Копировать
let mut seen = Vec::new();
let first = [1, 2, 3].iter().inspect(|n| seen.push(**n)).find(|n| **n == 2);
assert_eq!(first, Some(&2));
assert_eq!(seen, vec![1, 2]);
Если основной путь стабилен, ранний выход и повторный вход можно не воспроизводить отдельно. Контракт `iter` считался бы одинаковым при любом состоянии входа.
Если сценарий проходит в debug-сборке, в release и на другой целевой платформе результат будет тем же.
Отсутствие сообщения инструмента означает, что опасная ветвь была выполнена и признана корректной. Дополнительный сценарий вокруг `Vec::new` при таком толковании уже не требуется.
Диагностика инструмента сама однозначно подсказывает безопасное исправление, поэтому разбирать контракт отдельно не нужно.
find прекращает обход после совпадения, поэтому inspect не увидит третий элемент.
Вопрос 5 из 25
Что нужно пересмотреть в использовании `iterator_is_lazy`, чтобы код стал корректным?
Rust Rust · Тестирование и инструменты Cargo Копировать
#[test]
fn iterator_is_lazy() {
let calls = std::cell::Cell::new(0);
let it = [1, 2].iter().map(|x| { calls.set(calls.get() + 1); x * 2 });
assert_eq!(calls.get(), 0);
assert_eq!(it.collect::<Vec<_>>(), vec![2, 4]);
assert_eq!(calls.get(), 2);
}
Клонировать захваченное состояние перед каждым вызовом `iterator_is_lazy`, не уточняя требуемый трейт вызова или время жизни.
Для итератора проверять пустой ввод, частичное потребление, порядок элементов и число вызовов; не ограничиваться итоговым collect на одном обычном наборе.
Продублировать реализацию для каждого известного типа вокруг `iterator_is_lazy`, вместо того чтобы исправить границы обобщения «Тестирование и инструменты Cargo».
Собирать каждый промежуточный итератор в Vec, чтобы ленивость не влияла на порядок. Сигнатура при этом почти не меняется, однако исходное предусловие остаётся скрытым. В результате `iterator_is_lazy` считали бы безопасным и на путях, которых пример не выполняет.
Заменить текущую форму `iterator_is_lazy` на `Box<dyn Trait>` во всех местах, не проверяя владение, объектобезопасность и стоимость вызова.
Вопрос 10 из 25
Какая часть механизма «Адаптеры» зафиксирована тестом `copied`?
Rust Rust · Адаптеры Копировать
let out: Vec<_> = [1, 2, 3].iter().copied().map(|n| n + 1).collect();
assert_eq!(out, vec![2, 3, 4]);
Диагностика инструмента сама однозначно подсказывает безопасное исправление, поэтому разбирать контракт отдельно не нужно. Дополнительный сценарий вокруг `copied` при таком толковании уже не требуется.
Если сценарий проходит в debug-сборке, в release и на другой целевой платформе результат будет тем же.
Результат можно считать доказательством свойства языка, даже если он зависит от конкретной библиотеки или платформы. Дополнительный сценарий вокруг `copied` при таком толковании уже не требуется.
Раз тест прошёл, производительность решения тоже можно считать подтверждённой. Дополнительный сценарий вокруг `copied` при таком толковании уже не требуется.
copied переводит Iterator<Item=&i32> в Iterator<Item=i32>, после чего map работает со значениями без двойного разыменования.
Вопрос 15 из 25
Какая правка выдержит ревью контракта «Адаптеры»?
Rust Rust · Адаптеры Копировать
let values = [1, 2, 3, 4];
let sum: i32 = values.iter().filter(|n| **n % 2 == 0).map(|n| n * 10).sum();
println!("{sum}");
Клонировать захваченное состояние перед каждым вызовом `values`, не уточняя требуемый трейт вызова или время жизни.
Добавить Clone ко всем trait bounds, даже если реализация использует только ссылки. При каждом таком вызове появляется отдельный владелец и оплачивается копирование данных. В результате `iter` считали бы безопасным и на путях, которых пример не выполняет.
Строить цепочку из адаптеров с ясными этапами; при сложных ссылочных уровнях использовать copied или destructuring, чтобы не скрывать типы звёздочками.
Заменить текущую форму `values` на `Box<dyn Trait>` во всех местах, не проверяя владение, объектобезопасность и стоимость вызова.
Продублировать реализацию для каждого известного типа вокруг `values`, вместо того чтобы исправить границы обобщения «Адаптеры».
Вопрос 25 из 25
Как устранить исходную ошибку, связанную с `into_iter`?
Rust Rust · Итераторы Iterator Копировать
let mut it = vec![10, 20].into_iter();
println!("{:?} {:?} {:?}", it.next(), it.next(), it.next());
Продублировать реализацию для каждого известного типа вокруг `vec`, вместо того чтобы исправить границы обобщения «Итераторы Iterator».
Клонировать захваченное состояние перед каждым вызовом `vec`, не уточняя требуемый трейт вызова или время жизни.
Принимать Iterator или IntoIterator по нужному контракту; не сохранять ссылку на временный итератор, который сразу уничтожается.
Собирать каждый промежуточный итератор в Vec, чтобы ленивость не влияла на порядок. Сигнатура при этом почти не меняется, однако исходное предусловие остаётся скрытым. Из этого следовало бы, что иной порядок операций для `into_iter` ничего не меняет.
Сделать трейт объектобезопасным удалением всех методов, которые возвращают Self, без альтернативного API.