Память для программы может быть выделена следующим образом:
- стек
- отвал
стек
Стек следует за последним в первом порядке. В стеке хранятся значения данных, размер которых известен во время компиляции. Например, переменная фиксированного размера i32 является кандидатом на выделение стека. Его размер известен во время компиляции. Все скалярные типы могут храниться в стеке, так как размер фиксирован.
Рассмотрим пример строки, которой присваивается значение во время выполнения. Точный размер такой строки не может быть определен во время компиляции. Так что это не кандидат на выделение стека, а на выделение кучи.
отвал
Куча памяти хранит значения данных, размер которых неизвестен во время компиляции. Он используется для хранения динамических данных. Проще говоря, куча памяти выделяется для значений данных, которые могут изменяться в течение жизненного цикла программы. Куча — это область в памяти, которая менее организована по сравнению со стеком.
Что такое собственность?
Каждое значение в Rust имеет переменную, которая называется владельцем значения. Каждые данные, хранящиеся в Rust, будут связаны с владельцем. Например, в синтаксисе — пусть age = 30, age является владельцем значения 30 .
-
Каждые данные могут иметь только одного владельца за раз.
-
Две переменные не могут указывать на одну и ту же область памяти. Переменные всегда будут указывать на разные области памяти.
Каждые данные могут иметь только одного владельца за раз.
Две переменные не могут указывать на одну и ту же область памяти. Переменные всегда будут указывать на разные области памяти.
Передача права собственности
Право собственности на стоимость может быть передано:
-
Присвоение значения одной переменной другой переменной.
-
Передача значения в функцию.
-
Возвращаемое значение из функции.
Присвоение значения одной переменной другой переменной.
Передача значения в функцию.
Возвращаемое значение из функции.
Присвоение значения одной переменной другой переменной
Основное преимущество Rust как языка — безопасность памяти. Безопасность памяти достигается за счет жесткого контроля над тем, кто может использовать что и когда ограничения.
Рассмотрим следующий фрагмент —
fn main(){ let v = vec![1,2,3]; // vector v owns the object in heap //only a single variable owns the heap memory at any given time let v2 = v; // here two variables owns heap value, //two pointers to the same content is not allowed in rust //Rust is very smart in terms of memory access ,so it detects a race condition //as two variables point to same heap println!("{:?}",v); }
В приведенном выше примере объявляется вектор v. Идея владения заключается в том, что только одна переменная связывается с ресурсом, либо v связывается с ресурсом, либо v2 связывается с ресурсом. Приведенный выше пример выдает ошибку — использование перемещенного значения: `v` . Это связано с тем, что право собственности на ресурс передается в v2. Это означает, что владение перемещено с v на v2 (v2 = v) и v становится недействительным после перемещения.
Передача значения в функцию
Владение значением также изменяется, когда мы передаем объект в куче замыканию или функции.
fn main(){ let v = vec![1,2,3]; // vector v owns the object in heap let v2 = v; // moves ownership to v2 display(v2); // v2 is moved to display and v2 is invalidated println!("In main {:?}",v2); //v2 is No longer usable here } fn display(v:Vec<i32>){ println!("inside display {:?}",v); }
Возвращаемое значение из функции
Право собственности, переданное функции, будет признано недействительным по завершении выполнения функции. Чтобы обойти это, пусть функция возвращает принадлежащий объект обратно вызывающей стороне.
fn main(){ let v = vec![1,2,3]; // vector v owns the object in heap let v2 = v; // moves ownership to v2 let v2_return = display(v2); println!("In main {:?}",v2_return); } fn display(v:Vec<i32>)->Vec<i32> { // returning same vector println!("inside display {:?}",v); }
Владение и примитивные типы
В случае примитивных типов содержимое одной переменной копируется в другую. Таким образом, никакого перехода собственности не происходит. Это потому, что примитивная переменная требует меньше ресурсов, чем объект. Рассмотрим следующий пример —
fn main(){ let u1 = 10; let u2 = u1; // u1 value copied(not moved) to u2 println!("u1 = {}",u1); }
Выход будет — 10.