Каждому, кто пишет на Rust рано или поздно приходится столкнуться с концепциями владения, Borrow checker-ом, с разницей в типах данных и их местонахождением в памяти.
Эта статья именно об этом.
Начнем с этих принципов.
- У каждого значения может быть только один владелец
Если по простому - когда вы объявили переменную и записали в нее какие либо данные - она становится их владельцем. Если вы присваиваете ее значение другой переменной - то последняя становится владельцем. А предыдущая отбрасывается.
Но тут следует обратить внимание на то, где хранятся данные.
Если данные хранятся в куче (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 (Строчной срез) - уже с первого символа говорит о том, что эта ссылка.
Что хранится в стеке :
- Целые числа (i8, i16, i32) или (u8, u16, u32).
- Значения типа Bool (true/false).
- Числа с плавающей точкой (f32, f64).
- Символы или "char".
- Списки (потому что количество элементов известно с самого начала).
- Кортежи (если полностью состоят из элементов, которые хранятся в стеке).
Что хранится в куче :
- String - строка (неизвестен окончательный размер).
- &str - срез (неизвестен окончательный размер + ссылка на оригинальную строку, с которой сделан срез).
- Vec - вектор (не имеет определенной конечной точки для хранения элементов).
- Box - умный указатель для хранения данных в куче (Heap).
Благодарю вас за внимание!