Учебное пособие по Rust: изучение Rust с нуля

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

Фактически, в 2020 году Rust был признан самым любимым языком программирования в стеке. Опрос разработчиков Overflow уже пятый год подряд. Многие разработчики настаивают на том, что Rust скоро обгонит C и C ++ из-за средства проверки заимствований Rust и решения давних проблем, таких как управление памятью и неявная или явная типизация.

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

Вот то, что мы рассмотрим сегодня:

  • Что такое Rust?
  • Hello World в Rust
  • Основы синтаксиса Rust
  • Промежуточный уровень Rust: владение и структуры
  • Система сборки Rust: Cargo
  • Дополнительные концепции для изучения далее

Мастер Rust все в одном месте

За половину времени станьте экспертом по Rust с практической практикой.

Полное руководство по программированию на Rust

Что такое Rust?

Rust — это многопарадигмальный статически типизированный язык программирования с открытым исходным кодом, используемый для создания операционных систем, компиляторов и другого оборудования для программных средств. Он был разработан Грейдоном Хоаром из Mozilla Research в 2010 году.

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

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

Почему вы должны изучать Rust?

Язык программирования Rust идеален для низкоуровневого системного программирования из-за его уникальной системы распределения памяти и его приверженности оптимизированному и безопасному параллелизму. Хотя он еще не распространен среди крупных компаний, он остается одним из языков с наивысшим рейтингом .

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

Hello World in Rust

Лучший способ понять Rust — это получить практическую практику. Мы рассмотрим, как написать вашу первую программу hello-world на Rust.

 fn main () {println! ("Hello World!");} 

Давайте разберем этот код на части.

  • fn

    fn — это сокращение от «Функция». В Rust (и большинстве других языков программирования) функция означает «расскажи мне некоторую информацию, я сделаю кое-что, а затем дам вам ответ».

  • main

    Основная функция — это то место, где запускается ваша программа.

  • ()

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

  • {}

    Они называются фигурными скобками или скобками. Они определяют начало и конец нашего тела кода. В теле будет указано, что делает основная функция.

  • println!

    Это макрос, очень похожий на функции. Это означает «напечатать и добавить новую строку». На данный момент вы можете рассматривать println как функцию. Разница в том, что он заканчивается восклицательным знаком (! ).

  • ("Hello, world!")

    Это список параметров для вызова макроса. Мы говорим «вызовите этот макрос, называемый println , с этими параметрами». Это похоже на то, как основная функция имеет список параметров, за исключением того, что макрос println имеет параметр. Позже мы узнаем больше о функциях и параметрах.

  • «Привет, мир!»

    Это строка. Строки — это набор букв (или символов), соединенных вместе. Мы помещаем их в двойные кавычки ( "), чтобы пометить их как строки. Затем мы можем передавать их для макросов, таких как println! и других функций, которые мы ‘ поиграю позже.

  • ;

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

Основы синтаксиса Rust

Теперь давайте взглянем на некоторые из основных частей программы Rust и способы их реализации.

Переменные и изменчивость

Переменные — это точки данных, которые сохраняются и маркируются для дальнейшего использования. Формат объявления переменных:

  let [variable_name] = [value];  

Имя переменной должно быть описательным это описывает, что означает значение. Например:

  let my_name = "Ryan";  

Здесь мы создали переменную с именем my_name и установите для него значение «Ryan».

Совет : всегда называйте переменные строчной буквой в начале и заглавные буквы для обозначения начала нового слова

В Rust переменные неизменяемы по умолчанию, что означает, что их значение нельзя изменить один раз он установлен.

Например, этот код выдаст ошибку во время компиляции:

 fn main () {let x = 5;  println! ("Значение x: {}", x);  х = 6;  println! ("Значение x: {}", x);} 

Ошибка из строки 4, где мы пытаемся установить x = 6 . Поскольку мы уже установили значение x в строке 2, мы не можем изменить это значение.

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

Представьте, что у нас есть functionA , который полагается на переменную, имеющую значение 10 и functionB , который изменяет ту же переменную. functionA будет сломан!

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

Чтобы переопределить это значение по умолчанию и создать изменяемую (изменяемую) переменную, объявите переменную как:

  let mut x = 5;  

Изменяемые переменные чаще всего используются как переменные-итераторы или переменные в структурах цикла while .

Типы данных

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

Rust имеет тег функция вывода типа , которая позволяет компилятору «сделать вывод», какой тип данных должна иметь ваша переменная, даже без вашего явного указания. Это позволяет вам сэкономить время при написании объявлений переменных для вещей с очевидными типами, такими как строка my_name .

Вы можете явно ввести свои переменные, используя : & [type] между именем переменной и значением.

Например, мы можем переписать наше объявление my_name как:

 let my_name = "  Райан "; //неявно типизированный let my_name: & str = "Ryan"; //явно набранный 

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

Представьте, что у нас есть переменная answer , которая записывает ответ пользователя в форму .

  let answer = "true";  

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

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

  let answer: bool =  true;  

Основные типы Rust:

  • Integer : Целые числа

  • Float : числа с десятичными знаками

  • Boolean : двоичный true или false

  • String : наборы символов, заключенные в кавычки

  • Char : Скалярное значение Unicode, представляющее определенный символ

  • Never : тип без значения, помеченный !

Функции

Функции — это коллекции связанного кода Rust, объединенные под сокращенным именем и вызываемые из где-нибудь в программе.

До этого момента мы использовали только базовую функцию main () . Rust также позволяет нам создавать собственные дополнительные функции, что важно для большинства программ. Функции часто представляют собой одну повторяемую задачу, например addUser или changeUsername . Затем вы можете повторно использовать эти функции, когда захотите выполнить то же поведение.

Функции вне main должны иметь уникальное имя и возвращаемый результат. Они также могут передавать параметры , которые представляют собой один или несколько элементов ввода для использования в функции.

Вот формат объявления функции:

  fn [functionName] ([parameterIdentifier]: [parameterType]) {[functionBody]}  
  • fn

    Это сообщает Rust, что следующий код является объявлением функции

  • [functionNamepting

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

  • ()

    Мы должны заполнить эти круглые скобки любыми параметрами, к которым функция должна иметь доступ. В этом случае нам не нужно передавать какие-либо параметры, поэтому мы можем оставить это поле пустым.

  • [ parameterIdentifier]

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

  • [parameterType]

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

  • {}

    Эти фигурные скобки отмечают начало и конец блока кода. Код между ними выполняется всякий раз, когда вызывается идентификатор функции..

  • [functionBody sizes********************************************************************************************* заполнитель для кода функции. Рекомендуется избегать включения любого кода, который не имеет прямого отношения к выполнению задачи функции.

Теперь мы добавим код, давайте переделаем наш hello-world как функцию с именем say_hello () .

  fn say_hello () {println! ("Привет, мир!");}  

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

После того, как функция создана, мы можем вызывать ее из других частей нашей программы. Поскольку программа начинается с main () , мы будем вызывать say_hello () оттуда.

Вот что такое полный программа будет выглядеть так:

 fn say_hello () {println! ("Привет, мир!");} fn main () {say_hello ();} 

Комментарии

Комментарии — это способ, которым вы можете добавить сообщение для других программистов. сразу понять, как устроена ваша программа. Они также полезны для описания цели сегмента кода, чтобы вы могли быстро вспомнить, что вы пытались выполнить позже. Итак, написание хороших комментариев может быть полезным как для вас, так и для других.

Есть два способа писать комментарии в Rust. Первый — использовать две косые черты //. Затем компилятор игнорирует все до конца строки. Например:

  fn main () {//Эта строка полностью игнорируется println! ("Hello, world!"); //Это напечатало сообщение//Все готово, пока!}  

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

  fn main (/* эй  , Я могу это сделать! */) {/* Первый комментарий */println! ("Hello, world!"/* Второй комментарий */); /* Все готово, пока!  третий комментарий */}  

Совет : вы также можете использовать комментарии, чтобы «закомментировать» разделы кода, которые вы не используете ‘не хочу, чтобы их выполняли, но, возможно, захочется добавить позже.

Условное операторы

Условные операторы — это способ создать поведение, которое возникает только в том случае, если набор условий истинен. Это отличный способ создания адаптируемых функций, которые могут обрабатывать различные программные ситуации без необходимости использования второй функции.

Все условные операторы имеют проверяемую переменную, целевое значение и оператор условия, например == , или > , который определяет, как они должны соотноситься. Статус переменной по отношению к целевому значению возвращает логическое выражение: true , если переменная удовлетворяет целевому значению, и false , если нет.

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

Это пример условного оператора if . По сути, мы говорим: «, если hasAccount имеет значение false, мы создадим учетную запись. Независимо от того, была ли у них существующая учетная запись или нет, мы затем войдем в систему пользователя в их учетную запись ».

Формат оператора if :

  if [variable] [conditionOperator] [targetValue] {[body body]}  

Три основных условных оператора: if , if else и while :

  • if : «Если условие истинно, выполнить, в противном случае пропустить».

  • если else : «Если условие истинно, выполнить тело кода A, в противном случае выполнить тело кода B.»

 fn main () {let is_hot = false;  if is_hot {println! («Жарко!»);  } else {println! («Не жарко!»);  }} 

Посмотрите, что произойдет, если вы измените значение is_hot на true
  • while : «Повторно выполнять тело кода, пока условие истинно, и переходить, когда условие становится ложным».
  while is_raining () {println! ("Эй, идет дождь!");}  

Совет : циклы while требуют, чтобы переменная checked была изменяемой. Если переменная никогда не изменится, цикл будет продолжаться бесконечно.

Продолжайте изучать Rust.

Станьте Rustacean, не просматривая обучающие видео. Текстовые курсы Educative дадут вам практический опыт, необходимый для длительного обучения.

Полное руководство по программированию на Rust

Промежуточный уровень владения Rust: владение и структуры

Владение

Владение — центральная особенность Rust и одна из причин, по которой он стал настолько популярны.

Все языки программирования должны иметь систему для освобождения неиспользуемой памяти. Некоторые языки, такие как Java, JavaScript или Python, имеют автоматические сборщики мусора, которые автоматически удаляют неиспользуемые ссылки. Низкоуровневые языки, такие как C или C ++, требуют, чтобы разработчики вручную выделяли и освобождали память, когда это необходимо.

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

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

Правила владения следующие:

  • Каждое значение в Rust имеет переменную, которая называется его

  • Может только быть одним владельцем за раз.

  • Когда владелец выходит за пределы области видимости, значение будет сброшено.

А пока давайте исследуем, как владение работает с функциями. Объявленные переменные выделяются, пока они используются. Если они передаются в качестве параметров другой функции, выделение перемещается или копируется другому владельцу для использования там.

  fn main () {let x = 5; //x имеет право собственности на 5 function (x);} fn function (number: i32) {//число получает право собственности на 5 let s = "memory"; //область действия s начинается, s действительна, начиная здесь//делаем что-то с s}//эта область теперь закончена, и s уже не действительна// 

Ключ Вывод, вот как по-разному обрабатываются s и x . x изначально владеет значением 5 , но должен передать право собственности на параметр number , как только он покидает область действия main () функция. Использование в качестве параметра позволяет продолжить выделение памяти 5 за пределами исходной функции.

С другой стороны, s не используется в качестве параметра и поэтому остается выделенным только тогда, когда программа находится внутри function () . После завершения function () значение s больше никогда не понадобится и может быть освобождено для освобождения памяти..

Структуры

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

Вы можете думать о них как о подобных классах из таких языков, как Java и Python.

Синтаксис объявления структуры:

  struct [идентификатор] {[fieldName]: [fieldType], [secondFieldName]: [secondFieldType]  ,}  
  • struct сообщает Rust, что следующее объявление будет определять тип данных struct.

  • [идентификатор] - это имя типа данных, используемого при передаче параметров, например string или i32` на строковые и целочисленные типы соответственно.

  • {} эти фигурные скобки отмечают начало и конец переменные, необходимые для структуры.

  • [fieldName] — это место, где вы называете первую переменную, которую должны иметь все экземпляры этой структуры . Переменные в структуре известны как fields .

  • [fieldType] — это где вы явно определяете тип данных переменной, чтобы избежать путаницы.

Например, вы можете создать struct Car , которая включает строковая переменная brand и целочисленная переменная year.

  struct Car {brand: String, year: u16,};  

Каждый экземпляр типа Автомобиль должен предоставлять значение для этих полей по мере его создания. Мы создадим экземпляр Car для представления отдельного автомобиля со значениями как для brand , так и для года .

  let my_car = Car {brand: String :: from ("BMW"),//явный тип для String year: 2009,};  

Так же, как когда мы определяем переменные с примитивными типами, мы определяем переменную Car с идентификатором, на который будет ссылаться позже.

  let  [variableIdentifier] = [dataType] {//fields}  

Оттуда мы можем использовать значения этих полей с синтаксисом [variableIdentifier]. [field ] . Rust интерпретирует это утверждение как «какое значение [поле] для переменной [идентификатор]?».

  println! («Моя машина - это {} от {}  ", my_car.brand, my_car. year);}  

Вот как выглядит наша структура вместе:

 fn main () {struct Car {brand: String, year: u16,}; let my_car = Car {brand:  String :: from ("BMW"), год: 2009,}; println! ("Моя машина - это {} из {}", my_car.brand, my_car.year);} 

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

Система сборки Rust: Cargo

Cargo — это система сборки и пакет Rust. менеджер. Это важный инструмент для организации проектов Rust путем перечисления необходимых для проекта библиотек (так называемых dependencies ), автоматической загрузки любых отсутствующих зависимостей и сборки программ на Rust из исходного кода.

Программы, с которыми мы имели дело до сих пор, достаточно просты, и нам не нужны зависимости. Когда вы начнете создавать более сложные программы, вам понадобится Cargo для доступа к возможностям инструментов, выходящих за рамки стандартной библиотеки. Cargo также полезен для загрузки проектов в ваше портфолио Github, поскольку они объединяют все части и зависимости.

Cargo автоматически устанавливается вместе с компилятором ( rustc ) и генератор документации ( rustdoc ) как часть Rust Toolchain, если вы загрузили Rust с официального сайта. Вы можете убедиться, что Cargo установлен, введя следующую команду в командной строке:

  $ cargo --version  

To создайте проект Cargo, запустите в CLI вашей операционной системы следующее:

  $ cargo new hello_cargo $ cd hello_cargo  

Первый команда создает новый каталог с именем hello_cargo . Второй выбирает новый каталог.

При этом создается манифест под названием Cargo.toml , который содержит все метаданные, необходимые Cargo для компиляции вашего пакета, и main.rs , отвечающий за компиляцию вашего проекта.

Чтобы увидеть их, введите:

  $ tree   

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

  [package] name = "hello_cargo" version = "1.43.0" developers = ["  Ваше имя  "] edition =" 2020 "[dependencies]  

Все зависимости будут перечислены в категории dependencies .

После завершения вашего проекта вы можете ввести команду $ cargo run , чтобы скомпилировать и запустить проект.

Дополнительные концепции для изучения дальше

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

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

К концу у вас будут навыки для выполнения ваших собственных проектов кодирования Rust и станьте на шаг ближе к профессиональному опыту.

Удачного обучения!

Продолжайте читать о низко- языки уровней

  • Изучите C ++ с нуля: полное руководство для начинающих

  • C vs C ++: объяснение различий в основных языках

  • 5 основных концепций программирования на C для разработчиков

Оцените статью
nanomode.ru
Добавить комментарий