Найти тему
Muhammed Mustafaev

Язык программирования Rust

Rust системный язык программирования, в первую очередь rust гарантирует производительность и безопасность памяти . У rust похожий синтаксис с C++. Rust может гарантировать безопасную работу с памятью используя систему Владения. Система владения это одна из уникальных особенностей языка rust. Благодаря этой системе управления памятью rust не приходится использовать автоматическую сборщик мусора (garbage colector) или ручное управление памятью.

Сборщик мусора присутствует в языках как Python, Java, C Sharp и др. При использовании сборщика мусора программа теряет не большую часть производительности. Это автоматическая управление памятью, программист особо не должен думать о памяти, сборщик мусора периодически удаляет объекты, которые уже не будут нужны(когда на объект 0 ссылок).

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

Система владения: память управляется с помощью системы владения с набором правил. Эти правила ни как не влияют на производительность. Эти правила проверяет компилятор только во время компиляции программы.
Правила владения:
1. Каждая значение имеет переменную которого зовут владельцем.
2. У значения может быть только один владелец.
3. Когда переменная покидает область видимости, то память очищается.
Это не влияет на производительность!!!

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

Примеры владения:

{
let s = "world";
}
переменная s ссылается на строковой литерал. Переменная действительно с момента его создания и до конца области видимости.
В данном случаи s хранится в стеке. И он не изменяемый.

Чтобы создать изменяемую строку нужно нужно использовать из строкового литерал функцию from
{
let mut s = String::from("hi");
s.push_str(", world");
println!("{}", s);
}
в данном примере s хранится в куче.
Это всё из за разной работы с памятью.

Способы взаимодействия переменных и данных: перемещение.
let x = 5;
let y = x;
в этом примере оба значение становятся равны 5. Это происходит потому что данные с фиксированным размером хранятся в стеке.
Теперь рассмотрим в случаи с изменяемой строкой.
let s1 = String::from("text");
let s2 = s1;
Тут всё работает по другому, сначала опишем как хранится s1 в памяти.
s1 хранит в стеке ссылку на кучу в котором находится значение (содержимое строки), длину и объем. Когда мы к s2 присвоили s1 мы скопировали данные с стек, не трогали данные с кучи. После выхода из области видимости rust автоматически вызывает функцию drop() которая очищает память кучи для это переменной. Получается раст пытается очистить два раза одну и туже память в кучу, это известно как ошибка двойного освобождения(double free) и является одной из ошибок безопасности памяти. Освобождение памяти дважды может привести к повреждению памяти. Rust эту проблему решает так: после присвоения s2 к s1, rust считает что s1 больше не действительна(она перешла к s2). Этот процесс называется перемещением(move). После выхода из области видимости rust не будет пытаться освободить дважды одну и туже память в куче.

Способы взаимодействия переменных и данных: клонирование.
Если нам все же нужно сделать глубокое копирование, скопировать данные и с кучи, то мы можем использовать метод clone().
let s1 = String::from("test");
let s2 = s1.clone();
Теперь после выхода с области видимости не будет ошибки
double free.
Этот метод является дорогим.

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

fn main() {
let s = String::from("test");
takes(s);

let x = 5;
copy(x);
}

fn takes(some_string: String) {
println!("{}", some_string); }

fn copy(some_integer: i32) {
println!("{}", some_integer); }

После вызова функции takes s станет не действительной, так как переместится в функцию

Возвращение значений и область видимости
Возвращение значений также может перемещать владение.

fn main() {
let s1 = ret_str();
let s2 = String::from("hi");
let s3 = test(s2); }

fn ret_str() -> String {
let some_string = String::from("hi");
some_string
}

fn test(a_string: String) -> String {
a_string
}

В этом примере показывается как из функции gives_ownership владение переходит к s1. В функцию takes_and_gives_back передается владение и в функции сразу же возвращается владение.
Если надо возвращать несколько объектов то это можно сделать с помощью кортежа
fn length(s: String) -> (String, usize) {
let length = s.len();
(s, length)
}