Основы Rust: синтаксис и структуры данных

от автора

Привет, Хабр!

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

В этой статье рассмотрим основы Rust.

Настройка окружения

На сайте раста есть инструкции по установке Rust на любую ОС. Процесс установки прост и интуитивно понятен и ее может выполнить любой школьник.

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

rustc --version

Команда должна вернуть текущую версию компилятора Rust, установленную на ПК.

Проверяем версию Cargo:

cargo --version

Если обе команды успешно возвращают версии инструментов, то все ок.

Создание первой программы на Rust

Для создания нового проекта на Rust, можно воспользоваться командой cargo new hello_rust. Cargo — это универсальный инструмент для управления зависимостями в расте. Команда создаст каталог с именем hello_rust, который будет содержать структуру проекта Rust. Внутри этого каталога лежит файл main.rs, в нем напишем код:

По классике поздорваемся с миром:

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

После этого можно перейти в терминал, перейти в каталог проекта и выполнить команду cargo run

Синтаксис Rust

Переменные и их мутабельность

Одна из особенностей Rust — это строгая система типов, которая помогает избежать множества ошибок на этапе компиляции:

let x = 42; // Неизменяемая переменная let mut y = 24; // Изменяемая переменная

let используется для объявления переменных. Первая переменная x неизменяема, что означает, что после присвоения значения 42, она не может быть изменена. Вторая переменная y объявлена как изменяемая, поэтому можно изменять ее значение.

Операторы и контроль потока

Rust поддерживает все базовые операторы, включая арифметические, логические и сравнительные операторы:

fn ariph() {     let a = 10;     let b = 3;          let sum = a + b; // Сложение     let difference = a - b; // Вычитание     let product = a * b; // Умножение     let quotient = a / b; // Деление     let remainder = a % b; // Остаток от деления  fn logic() {     let is_sunny = true;     let is_warm = false;          let is_good_weather = is_sunny && is_warm; // Логическое И     let is_raining = !is_sunny; // Логическое НЕ }  fn sravn() {     let x = 5;     let y = 10;          let is_equal = x == y; // Равно     let is_not_equal = x != y; // Не равно     let is_greater = x > y; // Больше     let is_less = x < y; // Меньше     let is_greater_or_equal = x >= y; // Больше или равно     let is_less_or_equal = x <= y; // Меньше или равно } 

Условные операторы: if, else if, else

fn main() {     let age = 25;      if age < 18 {         println!("Вы несовершеннолетний");     } else if age >= 18 && age < 65 {         println!("Вы взрослый");     } else {         println!("Вы пенсионер");     } }

Циклы: for, while

Циклы позволяют нам выполнять определенные блоки кода несколько раз. В Rust есть два основных типа циклов: for и while:

fn main() {     // Цикл for     for i in 1..=5 {         println!("Итерация {}", i);     }      // Цикл while     let mut counter = 0;     while counter < 3 {         println!("Повторение {}", counter);         counter += 1;     } }

В for используем диапазон чисел 1..=5 для выполнения блока кода пять раз. В случае цикла while, выполняем блок кода, пока значение переменной counter меньше 3, и увеличиваем его после каждой итерации.

Match-выражения

Match-выражения позволяют сравнивать значение с несколькими возможными вариантами и выполнять соответствующий блок кода:

fn main() {     let language = "Rust";      match language {         "Rust" => println!("Вы выбрали Rust - отличный выбор!"),         "Python" | "JavaScript" => println!("Тоже хорошие языки!"),         _ => println!("Неизвестный язык программирования"),     } }

Если значение соответствует «Rust», выводим сообщение о выборе Rust. Если оно соответствует «Python» или «JavaScript», выводим общее сообщение. В противном случае, используем _, чтобы обработать все остальные значения.

Объявление функций

fn main() {     // Вызов функции     greet("Alice");      // Вызов функции с возвращаемым значением     let result = add(3, 5);     println!("Сумма: {}", result); }  // Объявление функции без возвращаемого значения fn greet(name: &str) {     println!("Привет, {}!", name); }  // Объявление функции с возвращаемым значением fn add(a: i32, b: i32) -> i32 {     a + b }

Параметры функций

fn main() {     let a = 5;     let b = 3;     let sum = add(a, b);     println!("Сумма: {}", sum); }  fn add(x: i32, y: i32) -> i32 {     x + y }

add принимает два параметра x и y, их значения передаются из функции main при вызове функции add.

Возвращаемые значения функций

Возвращаемый тип указывается после параметров функции и определяет тип данных, который функция вернет:

fn main() {     let result = multiply(4, 6);     println!("Произведение: {}", result); }  fn multiply(a: i32, b: i32) -> i32 {     a * b // Это выражение будет возвращено из функции }

multiply возвращает произведение двух чисел типа i32.

Структуры данных

Целые числа

let integer: i32 = 42; // 32-битное целое число со знаком let unsigned_integer: u64 = 100; // 64-битное целое число без знака

Числа с плавающей точкой

let float: f32 = 3.14159265359; // 32-битное число с плавающей точкой let double: f64 = 2.71828182845; // 64-битное число с плавающей точкой (по умолчанию) 

Булевы значения

let is_rust_cool: bool = true; // Логическое значение true let is_open_source: bool = false; // Логическое значение false

Символы и строки

let char_type: char = 'A'; // Символ let string_type: &str = "Hello, Rust!"; // Строка (неизменяемая)

Векторы

В Rust векторы можно создавать и изменять в размере по мере необходимости:

fn main() {     // Создание вектора целых чисел     let mut numbers: Vec<i32> = Vec::new();          // Добавление элементов в вектор     numbers.push(42);     numbers.push(24);     numbers.push(12);          // Доступ к элементам вектора     let first = numbers[0];          // Итерация по вектору     for num in &numbers {         println!("Число: {}", num);     }          // Размер вектора     let length = numbers.len();          // Удаление элемента из вектора     let removed = numbers.pop(); }

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

Массивы

fn main() {     // Создание массива строк     let colors: [&str; 3] = ["Red", "Green", "Blue"];          // Доступ к элементам массива     let first_color = colors[0];          // Итерация по массиву     for color in &colors {         println!("Цвет: {}", color);     }          // Размер массива (известен на этапе компиляции)     let length = colors.len(); }

Создали массив colors, содержащий три строки. Массивы в Rust имеют фиксированный размер, который задается при объявлении.

Какой контейнер выбрать — вектор или массив? Выбор зависит от конкретной задачи. Если нужна динамичность и возможность изменять размер данных во времени, то векторы оч. хорошо подходят. Если же вы знаете точный размер данных заранее, то массивы более адекватным выбором.

Структуры

Структуры — это способ объединить несколько переменных разных типов в одну логическую единицу:

// Определение структуры Point struct Point {     x: f64,     y: f64, }  fn main() {     // Создание экземпляра структуры Point     let origin = Point { x: 0.0, y: 0.0 };          // Доступ к полям структуры     println!("Координаты точки: ({}, {})", origin.x, origin.y); }

Определили структуру Point, содержащую два поля типа f64x и y. Затем создали экземпляр структуры origin и получили доступ к полям.

Перечисления

// Определение перечисления Animal enum Animal {     Dog,     Cat,     Bird, }  fn main() {     // Использование перечисления     let pet = Animal::Dog;          // Проверка значения перечисления     match pet {         Animal::Dog => println!("Это собачка!"),         Animal::Cat => println!("Это котик!"),         Animal::Bird => println!("Это птиц!"),     } }

Определили перечисление Animal, которое может принимать одно из трех значений. Затем создали переменную pet и с помощью match сравнили ее значение с вариантами перечисления.

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


Также в Rust реализовано хорошее и безопасное управление памятью, у меня есть статья на эту тему: как работает управление памятью в Rust без сборщика мусора.

В целом Rust очень даже хороший ЯП и набирает свою популярность.

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


ссылка на оригинал статьи https://habr.com/ru/articles/789870/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *