Поймите, почему Rust — это язык безопасности и производительности, и изучите такие понятия, как владение и заимствование.
Rust — новичок в мире программирования. Rust — это современный язык системного программирования, оптимизированный для обеспечения безопасности и производительности. Многие приложения, такие как операционные системы (Redox, Firecracker), веб-браузеры, такие как Mozilla, веб-сборка, используют Rust
Я открыл для себя Rust в прошлом году, когда заинтересовался блокчейном Solana. С тех пор Rust стал моим любимым языком программирования. Он имеет некоторые мощные функции по сравнению с другими языками программирования. Думать о:
- В Rust есть абстракции с нулевой стоимостью
- Имеет встроенный параллелизм
- Предлагает права собственности и безопасность
- Впечатляющая документация
- Растущее сообщество
Есть причина, по которой разработчики выбрали Rust как самый любимый язык программирования в переполнении стека в 2015 году.
Изучать Rust сложнее, если вы пришли из других языков программирования, но оно того стоит.
Ключевым преимуществом Rust как языка является безопасность памяти. Вы достигаете безопасности памяти за счет жесткого контроля над тем, кто что может использовать и когда. Все остальные языки, с которыми я работал, имеют много проблем с управлением памятью и Rust; тем не менее, он очень умно управляет памятью.
Я изучаю Rust Ландшафт уже несколько месяцев, и я хочу найти время, чтобы объяснить некоторые простые концепции, потому что я верю, хотите ли вы изучать Rust или нет. Вы все еще можете извлечь огромную пользу, зная, что происходит под капотом на других языках.
Однако, прежде чем мы перейдем к таким понятиям, как заимствование и владение, я хочу сделать небольшое отступление. Давайте сначала попробуем немного разобраться в памяти.
Сборка мусора против ручного управления памятью
В большинстве языков сценариев, таких как C# или Java, нам не нужно беспокоиться о ручном управлении памятью, поскольку сборщик мусора делает это за нас. Сборщик мусора (GC) освобождает место, занятое неиспользуемыми объектами в программе.
Поскольку нам не нужно беспокоиться о памяти, у нас более быстрое время записи, не путайте со временем выполнения. Родные языки, такие как C++ или C, очень быстры, поскольку размер программы невелик. Но в настоящее время, поскольку аппаратное обеспечение является продвинутым, большинство компаний предпочитают языки сценариев, такие как Python или Javascript, абстрактное управление памятью.
Однако у GC есть свои проблемы. Первые утечки памяти все же могут произойти. Кроме того, у вас более медленное и непредсказуемое время выполнения и производительность. С ручным управлением памятью у вас нет этой проблемы. Вы можете управлять памятью и иметь более быстрое время выполнения. Вы должны быть осторожны с ошибками в памяти.
Но нам нужно лучшее из обоих миров. Таким образом, вы можете управлять памятью, но без ошибок и с меньшим размером программы.
Тем не менее, вы по-прежнему имеете более медленное время записи и более высокую кривую обучения в Rust при борьбе с проверкой заимствования. Rust обеспечивает разумный доступ к памяти с помощью концепции, называемой владением.
Но прежде чем мы поговорим об этом. Я хочу уделить больше времени разнице между стеком и кучей.
Стек против. куча
Распределение стека следует стратегии LIFO (последним пришел, первым ушел) для выделения памяти процессам с помощью операций push и pop. Каждый блок в памяти имеет фиксированный размер; Последняя запись в стеке доступна в любой момент.
Стек использует непрерывную память, где указатель с именем stack base указывает на первую запись стека, а другой указатель с именем top of stack указывает на последнюю запись стека.
Стек также поддерживает вызовы функций. Вызов функции может содержать набор записей стека, известный как кадр стека. Другое название кадра стека — активационная запись в контексте компилятора, так как в нем хранятся данные, используемые во время компиляции программы.
Фрейм стека состоит либо из адресов, либо из значений параметра функции и адреса возврата, который указывает, куда следует заменить элемент управления после завершения выполнения функции.
Определение кучи
Распределение кучи не следует какому-либо определенному подходу; вместо этого он допускает случайное назначение и переназначение памяти. Запрос назначения процессом возвращает указатель на выделенную область памяти в куче, и процесс получает доступ к выделенной области памяти через указатель.
В отличие от стека, где мы автоматически освобождаем память, мы осуществляем освобождение через запрос на освобождение. Куча создает дыры в распределении памяти, когда структуры данных создаются и становятся доступными, и она используется во время выполнения.
Нам нужно было понимать как стек, так и кучу, чтобы говорить о следующих концепциях в Rust.
Владение
Есть три правила, когда речь заходит о праве собственности в Rust.
- У каждого значения в Rust есть переменная, которая называется владельцем.
- Единовременно может быть только один владелец.
- Когда владелец выходит за рамки. Программа сбрасывает значение
Допустим, вы объявляете переменную v. Используемая здесь структура данных — это вектор. Это похоже на динамический массив или связанный список. Программа сохраняет переменную v (ее адрес) в стеке. Однако сами данные находятся в куче.
В строке 3 я присваиваю новой переменной v2 значение v. В языках более высокого уровня, таких как C# или Python. У меня не было бы проблем. Однако Rust делает все немного по-другому. Обычно у вас есть две переменные, назначенные одним и тем же данным в памяти, или у вас есть два указателя в памяти.
Указатель указывает, где мы храним значение в памяти — что-то вроде этикетки на коробке. Вы копируете один и тот же адрес, когда назначаете два указателя на один и тот же адрес памяти. Rust достаточно умен, когда дело доходит до доступа к памяти.
Вы можете ввести в свою программу так называемые гонки данных. Если, например, два потока во время выполнения должны получить доступ к одним и тем же данным, а поток A изменяет данные, это может привести к неожиданным результатам. Поток B может иметь дело с поврежденными данными при выполнении этого общего ресурса.
Поэтому, чтобы избежать такого сценария, Rust привязывает ресурс к переменной. По умолчанию в Rust вы перемещаете данные, а не копируете их.
В приведенном выше примере вы можете видеть, что мы получаем ошибку. Мы пытаемся сослаться на старое значение. Но Rust берет старую переменную и делает ее недействительной. Вот почему в строке 6 мы получаем ошибку еще до компиляции. Rust делает это с помощью функции под названием Проверка заимствования.
Однако Rust разрешает копирование в зависимости от того, где программа хранит переменную в памяти.
let t = 1; let t2 = t; println!("t = {}", t);
Здесь мы не перемещаем значение и выполняем копирование. Мы используем примитивный тип, такой как i32, для переменной t, хранящейся в стеке; мы знаем фиксированный размер в памяти и не используем указатель.
Мы храним их в куче для структур данных (я не знаю фактического размера памяти). Мы используем указатель для ссылки на них в куче. Так что мы не можем копировать это вокруг.
Заимствование
Чтобы понять заимствование, вам сначала нужно узнать о ссылках. Ссылка похожа на указатель; мы сохраняем данные в памяти и указываем на них.
Между указателями и ссылками есть много общего, но они все же разные.
- Ссылка не может быть нулевой, тогда как указатель может
- После создания вы не можете переназначить другое значение для ссылки
Помните, что с владением вы перемещаете значение, а не копируете его. Когда вы хотите передать код в функции, вы все равно хотите иметь право собственности. Поэтому вместо этого мы используем ссылки, чтобы сохранить право собственности.
Заимствование позволяет временно использовать переменную, а затем возвращать ее.
Я продемонстрирую на быстром примере.
Если бы переменная b не была объявлена внутри области видимости, вы не смогли бы распечатать a, так как b еще не выпустила a.
Итак, мы выполняем некоторые манипуляции с b, и в тот момент, когда b выходит из области видимости, он освобождает
Звездочка (*
) перед b говорит нам, что нам нужно значение ссылки a. Знак доллара — это наша ссылка на a.
&mut говорит нам, что у нас есть изменяемый тип. В Rust он неизменяем при инициализации переменной по умолчанию.
Заключительные мысли
Я только начал свой путь с Rust. У Rust бесконечные возможности для захватывающих проектов. В Rust есть что открыть, и для меня он может стать ведущим игроком в индустрии программирования.
Я буду больше изучать Rust в таких проектах, как робототехника, Интернет вещей, веб-сборка и блокчейн…
Если вы хотите быть в курсе, вы всегда можете подписаться на мою рассылку. Впереди еще много Rust ;-)