Комментарии 5
Для пытливых умов есть замечательный материал, модель Stacked Borrows. Это экспериментальная формализация, которая пытается строго определить, какие комбинации заимствований допустимы в Rust.
Уже два года как есть ещё и Tree borrows, более разрешительная модель, которая имеет больше шансов стать окончательной.
А вообще, если запустить такой код под специальным интерпретатором Miri, он сразу же ругается на нарушение правил заимствования. Другими словами, Rust сдал нас с потрохами: мы попробовали соврать компилятору, будто
&mutуникальна, а сами сунули ему два, и он нас за это наказывает.
В самом первом примере с двумя мутирующими указателями вовсе нет этой проблемы - там нет двух уникальных ссылок, для этого указатели и применяются, чтобы обходить это правило unique ref XOR multiple shared ref. И Miri вовсе не ругается, как вы обшибочно написали не проверив:
Если из
&mutсделать сырой указатель, а потом снова создать&mut(через тот же сырой), компилятор ранее мог потерять noalias, потому что не был уверен, не алиасится ли новый указатель с кем-то ещё.
Компилятору вовсе незачем терять noalias, ведь должно соблюдаться правило уникальности уникальной ссылки (т.е. &mut) - а в случае unsafe преобразования указателя в ссылку это правило целиком на ответственности программиста
Таким образом, компилятор разрешает такой мув, зная, что автор
UnsafeCellвзял на себя ответственность за соблюдение необходимых гарантий.
Речь конечно же о Cell, а не о RefCell, как ошибочно написали. Последний не имеет гарантий, предоставляя наружу сырые указатели, а вот первый как раз является safe-обёрткой.
И "мув" тут описка - видимо имеется ввиду мут-изменение значения в Cell.
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}Здесь второму аргументу достаточно быть иммутабельным - и всё так же гарантируется уникальность и будет оптимизация
Как Rust думает о памяти: &mut, provenance и noalias