Знайте 3 правила, которые лежат в основе системы владения Rust.

За последние несколько месяцев я был заинтригован языком программирования Rust, особенно его моделью памяти и правами собственности.

Сначала я думал, что это просто еще один язык системного программирования, который я могу выучить за несколько недель, написав несколько примеров приложений. Но затем я столкнулся с многочисленными препятствиями, работая с его моделью владения.

Мне потребовались недели, чтобы действительно понять основные принципы, на которых написан RUST. И теперь я не могу перестать учиться и пробовать больше.

В этом посте я поделюсь некоторыми принципами владения на простом примере.

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

Для начала обратитесь к структуре данных ниже:

В мире аналитики данных событие — это структура данных, состоящая из пар ключ-значение. Это точки данных, отправленные в службу сбора данных. События обычно могут быть названы для удобочитаемости. Мы будем работать с этой структурой событий на протяжении всего этого руководства и познакомимся с основами правил владения Rust.

Нет сборщика мусора

Прежде чем мы углубимся в правила, важно понять, что в Rust нет сборщика мусора, как в других языках программирования высокого уровня. Он также не имеет ручного управления памятью, как C/C++, для большинства частей. Поэтому это предпочтительнее, когда нам нужна производительность, а также безопасность памяти.

Когда дело доходит до управления памятью в стеке/куче, в Rust есть несколько простых правил для управления объектами и памятью. Rust гарантирует, что наша программа не сделает ошибок при управлении памятью — при условии, что мы придерживаемся определенных правил.

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

Ниже приведены правила работы с объектами и переменными Language.

У каждой переменной есть владелец

Рассмотрим блок кода, показанный выше. Мы инициализируем три переменные, а именно идентификатор клиента имени события и фактический объект события. Первое правило очень простое — у каждой переменной есть владелец. Это означает, что три значения, определенные выше, принадлежат трем переменным. Доступ к этим переменным возможен только внутри этой функции, и доступ за пределами этой функции запрещен. Когда я запускаю эту программу, мы видим ожидаемый результат, который является именем события, которое мы настроили.

Теперь давайте посмотрим на два других правила.

Допускается только один владелец

В любой момент времени Rust допускает только одного владельца переменных. Как правило, во многих языках программирования используется концепция использования нескольких переменных для ссылки на одно и то же значение. Например, в JAVA можно написать

String name = "Sam" ; 
String sam = name; 
System.out.println(name); 
System.out.println(sam);

Это отлично подходит для Java. Он выводит оба значения.

Теперь давайте попробуем сделать то же самое в Rust.

Мы попытались скопировать исходную ссылку и сохранить ее в другой переменной, чтобы использовать их обе в операторе печати. Угадайте, что с этим произойдет.

Ниже приведен вывод, когда мы пытаемся запустить это.

Здесь мы просто использовали другое имя переменной для ссылки на одно и то же событие и выводили их. Но Русту это совсем не нравится.

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

Технически, когда мы пытаемся создать новую переменную и ссылаемся на исходное событие, мы намеревались создать двух владельцев, указывающих на одни и те же данные.

Это не разрешено согласно первому и второму правилам. Чтобы гарантировать, что всегда существует только один владелец, rust переносит значение в эту новую переменную,обозначенную new_event_copy_ref. Итак, как только мы назначаем старую переменную новой переменной события, эта новая переменная указывает на место в памяти исходного события.

С этого момента мы не можем использовать исходную переменную, потому что она не существует. Данные все еще существуют, но у них новый владелец. RUST немедленно удаляет исходную переменную и очищает ее.

Таким образом, когда мы пытаемся напечатать исходное имя события, используя переменную new_event, мы получаем сообщение об ошибке, в котором четко указано Value borrowed after move. И все эти проверки происходят во время компиляции. Таким образом, мы гарантируем, что у нас нет ссылок, указывающих на недопустимые области памяти при запуске нашей программы.

Теперь рассмотрим третье правило.

Переменные вне области видимости автоматически удаляются

Когда переменная выходит за пределы области видимости, Rust немедленно удаляет переменную и очищает ее. Когда мы говорили о том, что в Rust нет сборщика мусора, вот что происходит при его отсутствии.

Таким образом, единственный раз, когда можно использовать переменные и обращаться к их ячейкам памяти, — это когда переменная находится в области видимости. Давайте возьмем пример, чтобы понять это.

Давайте сначала разберемся с «блоком области видимости». (Приведенный выше код может показаться немного другим, если вы используете другой язык программирования).

Область действия — это блок, обозначаемый открывающими и закрывающими фигурными скобками. {}. Он может быть вложен в функцию или может быть новым вызовом функции, имеющим собственную область видимости. В приведенном выше примере мы создали событие во внутренней области видимости.

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

По этой логике и по примеру из нашего второго правила можно предположить, что в этом случае компилятор будет жаловаться. И в этот раз мы правы. Ниже приведена ошибка, которую вы получаете при компиляции этой программы.

error[E0425]: cannot find value `new_event` in this scope
  --> analytix/core/src/models.rs:49:71
   |
49 |         println!("Original event name is {} . New Event Name is {}" , new_event.name , new_event_copy_ref.name)
   |                                                                       ^^^^^^^^^ not found in this scope

Как и ожидалось, эта переменная не была найдена в области видимости.

Эти три правила составляют основу системы владения Rust и служат хорошей отправной точкой для понимания более сложных сценариев, таких как разделяемые состояния, параллелизм и управление памятью.

Сложность управления памятью оставлена ​​на усмотрение языка, и мы, разработчики, следуем этим правилам, чтобы писать чистый и эффективный код (сначала это непросто, но со временем становится лучше).

Следуя этим правилам, rust не только гарантирует безопасность памяти для разработчиков, но и делает их лучшими программистами. Помимо этого, он также дает программам прирост производительности, близкий к C++, без сложностей с управлением памятью.

За несколько месяцев использования Rust я столкнулся с множеством препятствий при работе с этими правилами. В конце концов, я разработал способ действительно думать об упрощении модели памяти, а также кода (хотя мне еще предстоит пройти долгий путь). Я бы все же сказал, что я новичок в Rust. Но я люблю это!

Want to Connect?
Originally published at https://shanmukhsista.com