Найти тему
Coding Corner

Немного о концепциях владения и хранении типов данных.

Каждому, кто пишет на Rust рано или поздно приходится столкнуться с концепциями владения, Borrow checker-ом, с разницей в типах данных и их местонахождением в памяти.

Эта статья именно об этом.

Начнем с этих принципов.

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

Если по простому - когда вы объявили переменную и записали в нее какие либо данные - она становится их владельцем. Если вы присваиваете ее значение другой переменной - то последняя становится владельцем. А предыдущая отбрасывается.

Но тут следует обратить внимание на то, где хранятся данные.

Если данные хранятся в куче (Heap) - то владение будет передано следующей переменной и сработает принцип описанный выше. Пример для понимания.

Пример :

let x : String = String::from("Hello");

let y = x // В данном случае владение будет передано y, а x будет отброшен.

Если данные хранятся в Stack - то будет просто создана копия, вы по прежнему сможете взаимодействовать с исходником.

2. У каждого значения есть владелец.

Тут на самом деле и объяснять особо нечего, когда создаете переменную и записываете в нее значения - за ней закрепляется право на владение.

3. Когда владелец выходит из зоны видимости - значение отбрасывается и память освобождается.

Пример :

fn main() {

{ // На этой круглой скобке начинается зона видимости.

let sample : String = String::from("Sample")

} // На этой заканчивается. Все значения созданные внутри - отбрасываются.

println!("{}", sample) // Мы не можем использовать print на отброшенном значении. Оно было отброшено в результате выхода из зоны видимости выше.

}

Чтобы передавать ссылку на объект без передачи владения используется Амперса́нд или "&". Таким образом мы говорим компилятору, что всего лишь заимствуем нужное значение на время или создаем ссылку. И по выходу из зоны видимости уничтожается ссылка а не сам объект. И мы можем дальше его использовать.

Теперь поговорим немного о том, какие типы данных где хранятся.

Я не буду писать огромные и тяжелые таблицы, скажу только одно - все данные, размер которых известен компилятору до старта программы - хранятся в Stack. Если ему неизвестен размер, как, например, с типом String - то хранится он будет в куче (Heap). Иными словами в куче хранятся динамичные типы данных.

Вы так-же легко можете определить где находится объект просто посмотрев на тип. Например тип данных &str (Строчной срез) - уже с первого символа говорит о том, что эта ссылка.

Что хранится в стеке :

  1. Целые числа (i8, i16, i32) или (u8, u16, u32).
  2. Значения типа Bool (true/false).
  3. Числа с плавающей точкой (f32, f64).
  4. Символы или "char".
  5. Списки (потому что количество элементов известно с самого начала).
  6. Кортежи (если полностью состоят из элементов, которые хранятся в стеке).

Что хранится в куче :

  1. String - строка (неизвестен окончательный размер).
  2. &str - срез (неизвестен окончательный размер + ссылка на оригинальную строку, с которой сделан срез).
  3. Vec - вектор (не имеет определенной конечной точки для хранения элементов).
  4. Box - умный указатель для хранения данных в куче (Heap).

Благодарю вас за внимание!