💡 Инструкция: Выберите один ответ из пяти. На 25 вопросов отведено 70 минут. В каждом вопросе верен только один вариант. После завершения вы увидите общий результат, результаты по 5 тематическим шкалам и подробные объяснения.
Вопрос 18 из 25
К какому результату приводит последовательность вокруг `std::rc::`?
Rust Rust · Слабые ссылки Weak Копировать
use std::rc::{Rc, Weak};
struct Node { parent: Weak<Node> }
let root = Rc::new_cyclic(|me| Node { parent: me.clone() });
println!("{}", root.parent.upgrade().is_some());
Код компилируется, но weak::upgrade всегда возвращает Rc, пока существует сама Weak-ссылка. Из этого следовало бы, что иной порядок операций для `clone` ничего не меняет.
Сборка пройдёт, поскольку weak поддерживает сильный счётчик и поэтому не позволяет владельцу исчезнуть.
Rust не примет такую запись, поскольку используется Weak для обратной ссылки. До последней строки и наблюдаемого результата программа при таком разборе не доходит.
Код печатает true, пока существует root: Weak не увеличивает сильный счётчик, но может временно получить Rc через upgrade.
Код печатает true, пока существует root: Weak не увеличивает сильный счётчик, но может временно получить Arc через upgrade.
Вопрос 21 из 25
Как изменить фрагмент с `std::rc::Rc`, чтобы дефект не повторился?
Rust Rust · Счётчик ссылок Rc Копировать
use std::rc::Rc;
let a = Rc::new(String::from("shared"));
let b = Rc::clone(&a);
println!("{}", Rc::strong_count(&a));
drop(b);
println!("{}", Rc::strong_count(&a));
Заменить Arc на сырой указатель: атомарный счётчик нужен только для скорости, а не для владения. Интерфейс получает совместное владение или синхронизацию даже там, где исходная задача их не требовала. Контракт `std::rc` считался бы одинаковым при любом состоянии входа.
Клонировать счётчик перед каждой операцией `std::rc::Rc`, не устраняя цикл владения или конфликт динамического заимствования.
Использовать Rc для совместного владения в одном потоке; изменение моделировать отдельно через Cell или RefCell только при ясном контракте.
Заменить все владельцы на Rc<RefCell<_>>, включая данные, которые передаются между потоками. Интерфейс получает совместное владение или синхронизацию даже там, где исходная задача их не требовала. Тогда поведение `std::rc` при раннем выходе выводили бы из обычного пути.
Заменить указатель вокруг `std::rc::Rc` на `Arc` независимо от наличия потоков, не проверяя изменяемость и свойства данные этого фрагмента.