Изменяемые ссылки

Последнее обновление: 15.04.2021

По умолчанию ссылки, как и переменные, нельзя изменять. То есть по умолчанию мы не можем изменить значение, на которое ссылается ссылка. Например:

fn main(){
	
	let message = "hello".to_string();
	println!("До изменения: {}", message);
	change_message(&message);	// !Ошибка - значение по ссылки нельзя изменять по умолчанию
	println!("После изменения: {}", message);
}

fn change_message(mes: &String){
	
	mes.push('!');
}

Здесь для изменения значения по ссылке определена функция change_message(). У структуры String есть метод push(), который добавляет к строке один символ. В данном случае мы пытаемся добавить к строке "hello" символ "!", то есть, чтобы в итоге получилась строка "hello!". Однако при компиляции мы получим ошибку, поскольку по умолчанию значение по ссылке нельзя изменять:

Mutable reference и изменение ссылки в Rust

Чтобы значение по ссылке все таки можно было изменять, необходимо использовать изменяемую ссылку (mutable reference), которая определяется с помощью оператора &mut:

fn main(){
	
	let mut message = "hello".to_string();
	println!("До изменения: {}", message);
	change_message(&mut message);
	println!("После изменения: {}", message);
}
fn change_message(mes: &mut String){
	
	mes.push('!');
}

Здесь надо отметить три момента. Прежде всего, поскольку будет изменяться значение переменной, она должна быть определена с оператором mut:

let mut message = "hello".to_string();

Во-вторых, параметр-ссылка функции, через который надо изменять значение, определяется как изменяемая ссылка с &mut:

fn change_message(mes: &mut String){

В-третьих, при передаче ссылки в функцию значения перед ним также указывается оператор &mut:

change_message(&mut message);

В итоге, эта программа будет нормально компилироваться и одарит нас следующим консольным выводом:

До изменения: hello
После изменения: hello!

Подобным образом можно определять переменные-изменяемые ссылки:

fn main(){
	
	let mut s1 = "hello".to_string();
	let s2 = &mut s1;
	s2.push('!');
	println!("{}", s1);	// hello!
}

Следует отметить, что изменяемые ссылки имеют одно ограничение: в рамках одной области видимости может существовать только одна изменяемая ссылка. Например, следующий код не скомпилируется:

fn main(){
	
	
	let mut s1 = "hello".to_string();
	let s2 = &mut s1;	// первая изменяемая ссылка
	let s3 = &mut s1;	// вторая изменяемая ссылка
	s2.push('!');
	println!("{}", s1);	// hello!
}

В данном случае в одной области видимости - функции main определены две изменяемые ссылки - s2 и s3. Однако мы можем использовать вложенные области видимости, которые располагаются до определения изменяемых ссылок во внешних областях видимости:

fn main(){
	
	let mut s1 = "hello".to_string();
	// let s2 = &mut s1;	// если определить здесь, будет ошибка
	{
		let s3 = &mut s1;
		s3.push('?');
	}
	let s2 = &mut s1;
	s2.push('!');
	println!("{}", s1);	// hello?!
}

Одна переменная-изменяемая ссылка - s3 определена в анонимном блоке, который заканчивает свою работу ДО определения второй изменяемой ссылки - s2. Соответственно никаких конфликтов между ссылками не возникнет.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850