Ownership

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

Для управления данными в куче в Rust применяется такая концепция как ownership (можно перевести как "владение", "принадлежность"). Она является одной из характерных возможностей и особенностей языка Rust, которая позволяет гарантировать безопасность памяти.

Ownership имеет следующие аспекты:

  • Каждое значение в Rust имеет переменную, которая называется "владельцем" (owner).

  • У значения в один момент времени может быть только один владелец.

  • Когда владелец выходит за пределы области видимости/контекста, в котором он определен, его значение удаляется из памяти. Для этого Rust автоматически вызывает специальную функцию - drop(), которая очищает память.

Рассмотрим простейшую ситуацию:

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

	println!("s1: {}", s1);			// !Ошибка - s1 теперь нельзя использовать
	println!("s2: {}", s2);
}

Вначале определяем переменную s1, которая является владельцем строки "hello". Строка "hello" хранится в куче.

Куча heap in Rust

Потом меняем владельца, присваивая значение s1 переменной s2.

let s2 = s1;

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

Ownership in Rust

А переменная s1 теперь становится неинициализированной, и соответственно нам ее нельзя использовать. В итоге при компиляции этого кода мы получим ошибку на строке

println!("s1: {}", s1);	// !Ошибка - s1 теперь нельзя использовать
Ownership in Rust

Хотя мы можем заново инициализировть переменную s1, присвоив ей какое-либо значение:

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

	s1 = "world".to_string();	// s1 - владелец строки "world"
	println!("s1: {}", s1);		// s1: world
	println!("s2: {}", s2);		// s2: hello
}

Смена владельца в функции

Передача значения параметру в функцию аналогична присвоению значения переменной:

fn main(){
	
	let s1 = "hello".to_string();	// s1 - владелец строки "hello"
	println!("s1: {}", s1);
	
	display_message(s1);

	println!("s1: {}", s1);		// !Ошибка - переменная s1 неинициализирована
}

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

Здесь значение переменной s1 передается параметру message при вызове функции display_message():

display_message(s1);

Это приводит к тому, что опять же переменная s1 теряет владение над строкой "hello", которое переходит к параметру message.

В итоге опять же при компиляции мы получим ошибку на строке:

println!("s1: {}", s1);		// !Ошибка - переменная s1 неинициализирована
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850