Ссылки

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

В прошлой теме рассматривалась тема владения или ownership, в частности, рассматривалась смена владения, после которого переменную-прошлого владельца нельзя было использовать без повторной инициализации:

fn main(){
	
	let s1 = "hello".to_string();	// s1 - владелец строки "hello"
	let s2 = s1;					// смена владельца на s2
	
	// println!("s1: {}", s1);		// !Ошибка - переменная s1 неинициализирована
	println!("s2: {}", s2);		// s2: hello
}

В данном случае после присвоения let s2 = s1 происходит смена владельца строки "hello" с переменной s1 на s2. После этого переменную s1 без повторной инициализации мы не можем использовать.

Такое поведение не всегда может быть желательно. Возможно, мы затем сохранить владение для переменной s1, но при этом также присвоить ее значение переменной s2. Одним из решений данной проблемы является применение ссылок (reference).

Для получения ссылки на переменную применяется оператор & (амперсанд), который ставится перед переменной:

&переменная

После установки ссылки на переменную другими переменными, эта переменная сохраняет владение своим значением. Рассмотрим на примере:

fn main(){
	
	let s1 = "hello".to_string();	// s1 - владелец строки "hello"
	let s2 = &s1;					// s2 получает ссылку на значение переменной s1
	
	println!("s1: {}", s1);		// s1: hello
	println!("s2: {}", s2);		// s2: hello
}

В данном случае переменная s2 в качестве значения получает не само значение переменной s1 (то есть строку "hello"), а ссылку на него:

let s2 = &s1;

Поскольку здесь присваивается не сам объект String, а ссылка на него, то типом данных переменной s2 будет тип &String. То есть фактически мы могли бы написать:

let s2: &String = &s1;

Упрощенно визуально это можно представить следующим образом:

Ссылки reference в Rust и ownership

Переменная s2 ссылается на объект String s1, а тот хранит указатель на строку "hello" в куче. При этом s1 сохраняет владение и мы ее можем и дальше использовать:

s1: hello
s2: hello

При этом когда завершается область видимости переменной-ссылки s2, то значение, на которое она ссылается, не удаляется. Поскольку переменная-ссылка не владеет этим значением:

fn main(){
	
	let s1 = "hello".to_string();
	
	{
		let s2 = &s1;			// s2 получает ссылку на s1
		println!("s2: {}", s2);		// s2: hello
	}	// конец контекста переменной s2
	
	// s1 по прежнему можно использовать
	println!("s1: {}", s1);		// s1: hello
}

Параметры-ссылки

Параметры функций также могут представлять ссылки на другие объекты. В этом случае определение параметра выглядит следующим образом:

параметр: &тип_данных

Например, передадим в функцию ссылку:

fn main(){
	
	let s1 = "hello".to_string();
	display_message(&s1);	// message: hello
}

fn display_message(message: &String){
	
	println!("message: {}", message);	
}

Здесь параметр функции display_message () представляет ссылку на объект String и поэтому имеет тип &String:

fn display_message(message: &String){

При вызове функции этому параметру необходимо передать ссылку на объект String (но никак не сам объект String):

display_message(&s1);	// message: hello
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850