Короткий способ объяснить это состоит в том, что изменчивость в ссылках и изменчивость в переменных ортогональны друг другу. Две формы изменчивости связаны в том смысле, что мы можем только позаимствовать что-то из изменяемой переменной (или связывания). Кроме этого, каждая двоичная комбинация возможна в Rust:
reference mutability
-----------------------------
variable | x: &T | x: &mut T |
mutability |------------+----------------|
| mut x: &T | mut x: &mut T |
-----------------------------
Мы можем вспомнить множество примеров кода, иллюстрирующих, что можно сделать с такой переменной x. Например, неизменяемая переменная изменяемой ссылки может изменять другой элемент, но не саму себя:
let mut a = 5;
let mut b = 3;
let x: &mut i32 = &mut a;
*x = 10; // ok
x = &mut b; // nope! [E0384]
*x = 6;
Даже как поле в структуре, это не противоречит гарантиям безопасности Rust. Если переменная неизменно связана со значением структуры, каждое из полей также будет неизменным. В этом примере:
let mut x = 5;
let foo = Foo {
val: 6,
bar: Bar { val: 15 },
val_ref: &mut x
};
*foo.val_ref = 10;
Здесь не было применено никаких мутаций foo
: foo.val_ref
все еще указывает на x
. Первый может быть видоизменен, потому что он заимствован.
Ссылки проверяются независимо от заимствования. Параметр времени жизни 'a
в Foo
позволяет компилятору отслеживать заимствования.
Этот второй пример (показанный ниже) не работает, потому что из &Foo
мы можем получить ссылки только на его поля (например, на val_ref: &mut i32
). В свою очередь, для предотвращения алиасинга, &&mut i32
может быть приведен только к &i32
. Нельзя заимствовать данные изменчиво через неизменную ссылку.
let foo_ref = &foo;
*foo_ref.val_ref = 10; // error[E0389]
Руст не позволит мне сделать то же самое с помощью неизменной ссылки. Таким образом, неизменяемая ссылка имеет другое поведение, чем неизменяемая ссылка.
Точно!
Смотри также: