Rust (укр. Раст, дос. «Іржа») — сучасна мультипарадигмальна мова програмування загального призначення. Мова має сильну (строгу) типізацію і сфокусована на безпечній роботі з пам'яттю й забезпеченні високої рівночасності виконання завдань (можливість породжувати тисячі й навіть мільйони підпроцесів).
Rust | |
---|---|
Парадигма | імперативна, рівночасна, структурна, узагальнена, функційна |
Дата появи | 2010 |
Творці | Грейдон Гоар |
Розробник | Rust Project Developers |
Останній реліз | 1.73.0 (5 жовтень 2023) |
Система типізації | афінна[en], вивідна, іменна[en], статична, строга |
Під впливом від | Alef, C#, C++, Cyclone, Elm, Erlang, Haskell, Limbo, Newsqueak, OCaml, Ruby, Scheme, Standard ML, Swift |
Мова реалізації | Rust |
Платформа | Windows, Linux, macOS, FreeBSD, iOS, Android, крос-платформова програма і WebAssembly |
Операційна система | Linux, macOS, Windows, FreeBSD |
Ліцензія | Apache License 2.0 або ліцензія MIT |
Звичайні розширення файлів | .rs .rlib |
Репозиторій вихідного коду | github.com/rust-lang/rust |
Вебсайт | www.rust-lang.org |
Rust у Вікісховищі |
Початковий код проєкту поширюються під ліцензією MIT.
Історія Редагувати
Робота над мовою була розпочата працівником Mozilla Грейдоном Гоаром у 2006 році як персональний проєкт. У 2009 до розробки підключилася Mozilla, і у 2010 році мова була офіційно представлена на Mozilla Summit 2010. З 2021, після скорочень у Mozilla, розробку здійснює окремий фонд Rust Foundation. Мову названо за назвою родини грибів іржа. У 2010 році розробка мови була переведена з попередньої версії компілятора, яка була написана мовою OCaml, на компілятор, який написаний безпосередньо на Rust, з використанням LLVM як бекенду. У 2011 році новий компілятор успішно скомпілював сам себе.
Перший стабільний випуск мови Rust 1.0 відбувся 15 травня 2015 після п'яти років розробки, він ознаменував повну стабілізацію програмних інтерфейсів усіх бібліотек і мовних конструкцій. У процесі підготовки гілки Rust 1.0 програмні інтерфейси та можливості мови піддалися значній ревізії, після якої типово залишені лише повністю готові до застосування можливості, реалізація яких не змінюватиметься надалі. Усі інші особливості переведені в розряд експериментальних і винесені зі стандартного постачання.
Паралельно Mozilla Research розвиває експериментальний браузерний рушій Servo, написаний мовою Rust з підтримкою багатопотокового рендерингу вебсторінок і розпаралелюванням операцій з DOM, а компанія Samsung займається його портуванням на Android та ARM процесори.
Огляд Редагувати
За структурою, мова Rust нагадує C++, але істотно відрізняється в деяких деталях реалізації синтаксису та семантики, а також орієнтацією на блочну організацію структури коду, яка дозволяє реалізувати завдання у вигляді легковагих співпрограм. Автоматичне керування пам'яттю позбавляє розробника необхідності маніпулювання вказівниками й захищає від проблем, що виникають через низькорівневу роботу з пам'яттю, таких як звернення до ділянки пам'яті після її звільнення, розіменовування нульових вказівників, вихід за межі буфера тощо. Rust підтримує суміш імперативних, процедурних і об'єктно-орієнтованих методів з такими парадигмами, як функційне програмування і модель акторів, а також узагальнене програмування і метапрограмування, у статичних і динамічних стилях.
Синтаксис та особливості Редагувати
Особливості мови Редагувати
Базові можливості мови:
- Акуратна робота з пам'яттю — жодних нульових і завислих вказівників. Автоматичне керування пам'яттю без збирача сміття, самими гарантіями компілятора («контролер позичань»);
- Контроль мінливості. Об'єкти усталено немінливі (англ. immutable);
- Безпека динамічного виконання: обробка збоїв, винятки, ведення логу, RAII/dtors;
- Typestate: можливість визначення складних інваріантів, що контролюють структури даних.
- Явне керування пам'яттю, керування схемою розподілу пам'яті;
- Вкрай легкі завдання, що формуються у вигляді співпрограми. Легкість у породженні тисяч і мільйонів підпроцесів;
- Ітератори стека (фактично лямбда-блоки без розподілу купи);
- Статична, нативна компіляція зі створенням виконуваних файлів ELF, Portable Executable[en], Mach-O;
- Прямий і простий інтерфейс для коду на мові Сі.
- Мультипарадигмальна, функційна, імперативно-процедурна, підтримка паралельної моделі акторів;
- Функції вищого порядку зі зв'язуванням;
- Немає іменних типів чи ієрархії типів;
- Багатоплатформна, підтримується Windows, Linux, macOS, *BSD;
- Зберігання рядків у UTF-8, різноманітність низькорівневих типів;
- Працює з наявними нативними наборами інструментів: GNU Debugger, Valgrind, Shark тощо;
- Практична можливість порушення правил: можливість ігнорування правил безпеки, якщо чітко вказано, коли і як їх порушувати.
Володіння і контролер позичань Редагувати
Виразною особливістю Rust є система володіння даними, забезпечена частиною компілятора, що зветься контролером позичань (англ. borrow checker). Позичанням зветься створення посилання.
Правила володіння і позичання:
- дані завжди ініціалізовані;
- у даних у кожен момент може бути лише один володілець (змінна);
- під час знищення володільця (наприклад, під час виходу з області видимості) дані звільняються;
- на дані може бути кілька немінливих посилань;
- на дані може бути лише одне мінливе посилання, якщо немає немінливих.
Контролер позичань являє собою чи не найскладніше, з чим доводиться стикатися новим розробникам Rust. Він забороняє дуже багато практик, до яких можна легко звикнути в інших мовах програмування; натомість він захищає програміста від багатьох поширених в інших мовах помилок, таких як суперечності в даних (одна частина програми не може їх змінити, коли на них є посилання з іншої частини), зміна ітерованого об'єкта під час ітерації, гонитва даних і т. д.
Риси Редагувати
Риси (також іноді трейти, типажі, англ. traits) є однією з виразних особливостей Rust. Риси загалом нагадують інтерфейси в мовах програмування, що підтримують ООП, і позначають спільну поведінку різних типів.
Типи даних Редагувати
Примітивні типи Редагувати
Тип | Опис | Приклад |
---|---|---|
|
|
|
|
|
|
| Цілі числа розміром із вказівник (розмір залежить від платформи) |
|
| Числа з рухомою комою | -3f32 |
char | Символ (займає 4 байти) |
|
str |
|
|
bool | Булевий тип (займає 1 байт) |
|
[T] | Зріз — динамічно змінюване представлення в суміжній послідовності |
|
! | Тип «ніколи»[en] | let x = { return 123 }; |
Складені типи Редагувати
Тип | Опис | Приклад |
---|---|---|
(T, U, …) |
|
|
[T; N] |
| [i64; 10] (масив з 10 чисел типу i64 ) |
Типи зі стандартної бібліотеки Редагувати
Тип | Опис | Приклад |
---|---|---|
String | Динамічний рядок, що зберігає дані в купі |
|
Option<T> | Тип-опція[en] |
|
Result<T, E> | Обробка помилок |
|
Vec<T> | Вектор (динамічний масив) |
|
VecDeque | Двобічна черга на основі циклічного буфера | let mut buf = VecDeque::new(); buf.push_back(3); buf.push_back(4); buf.push_back(5); assert_eq!(buf.get(1), Some(&4)); |
LinkedList<T> | Зв'язаний список | let mut my_list = LinkedList::new(); my_list.push_back('b'); my_list.push_back('c'); |
HashMap<K, V> | Геш-таблиця | let mut player_stats = HashMap::new(); player_stats.insert("damage", 1); player_stats.entry("health").or_insert(100); |
BTreeMap<K, V> | Б-дерево | let mut solar_distance = BTreeMap::from([ ("Mercury", 0.4), ("Venus", 0.7), ]); solar_distance.entry("Earth").or_insert(1.0); |
HashSet | Множина на основі геш-таблиці | let mut books = HashSet::new(); books.insert("A Dance With Dragons".to_string()); books.insert("To Kill a Mockingbird".to_string()); books.insert("The Odyssey".to_string()); |
BTreeSet | Множина на основі Б-дерева | let mut planets = BTreeSet::new(); planets.insert("Mars"); planets.insert("JUpiter"); |
BinaryHeap | Двійкова купа | let mut heap = BinaryHeap::new(); heap.push(1); heap.push(5); heap.push(2); |
Вказівники Редагувати
Тип | Опис | Приклад |
---|---|---|
| Посилання (немінливі та мінливі) | let x_ref = &x; let x_ref = &mut x; |
|
| let x_ptr = &x as *const T; let x_ptr = &mut x as *mut T; |
Визначені користувачем типи Редагувати
Тип | Опис |
---|---|
struct | Структура |
union |
|
enum |
|
Приклади Редагувати
Наведені нижче приклади є робочими під час збірки за допомогою стабільної версії компілятора Rust 1.63.0, видання 2021.
fn main() { println!("hello, world"); }
Три версії реалізації функції пошуку факторіала, у рекурсивному та ітеративному способах:
// Умовна інструкція, що показує можливість неявного повернення значення (implicit return). // На відміну від C++ і схожих мов, у Rust інструкція «if» насправді є виразом, і може повертати значення. // Якщо у функції не вказано явного return, повертається останнє значення в тілі функції. fn recursive_factorial(n: u32) -> u32 { if n <= 1 { 1 } else { n * recursive_factorial(n - 1) } } fn iterative_factorial(n: u32) -> u32 { // Змінні оголошуються ключовим словом `let`. // Ключове слово `mut` робить змінні мінливими (дозволяє змінюватися) let mut i = 1u32; let mut result = 1u32; while i <= n { result *= i; i += 1; } return result; // Явне повернення значення, на відміну від попередньої функції } fn iterator_factorial(n: u32) -> u32 { // Ітератори мають багато методів для трасформації // |accum, x| визначає анонімну функцію. // Оптимізації на кшталт вбудування тіла функції дозволяють інтервалу // і fold досягати продуктивності, подібної до iterative_factorial. (1..=n).fold(1, |accum, x| accum * x) } fn main() { println!("Recursive result: {}", recursive_factorial(10)); println!("Iterative result: {}", iterative_factorial(10)); println!("Iterator result: {}", iterator_factorial(10)); }
Демонстрація вбудованих у Rust унікальних розумних вказівників, разом з типами-сумами[en] та методами:
use IntList::{Node, Empty}; // Ця програма визначає рекурсивну структуру даних та реалізує для неї методи. // Рекурсивні структури даних потребуть шару розіменування, який тут забезпечується // унікальним вказівником, побудованим за допомогою конструктора `Box::new`. Вони // аналогічні бібліотечному типу C++ `std::unique_ptr`, хоча й мають більше статичних // гарантій безпеки. fn main() { let list = IntList::new().prepend(3).prepend(2).prepend(1); println!("Sum of all values in the list: {}.", list.sum()); println!("Sum of all doubled values in the list: {}.", list.multiply_by(2).sum()); } // `enum` визначає тип-суму, що може бути одним з декількох різних видів значень під час виконання. // Тут тип або не міститиме значення, або міститиме значення і вказівник на інший `IntList`. enum IntList { Node(i32, Box<IntList>), Empty } // Блок `impl` дозволяє визначати методи для типу. impl IntList { fn new() -> Box<IntList> { Box::new(Empty) } fn prepend(self, value: i32) -> Box<IntList> { Box::new(Node(value, Box::new(self))) } fn sum(&self) -> i32 { // Вирази `match` є типовим способом застосування зіставлення із шаблоном // і дещо схожі на інструкцію `switch` із C та C++. match *self { Node(value, ref next) => value + next.sum(), Empty => 0 } } fn multiply_by(&self, n: i32) -> Box<IntList> { match *self { Node(value, ref next) => Box::new(Node(value * n, next.multiply_by(n))), Empty => Box::new(Empty) } } }
Проста демонстрація легковагих можливостей рівночасності Rust:
// Ця функція створює десять рівночасно виконуваних потоків. // Для перевірки можете запустити програму кілька разів і побачити // зміну порядку, у якому виводяться повідомлення різних потоків. fn main() { // Цей рядок немінливий і тому різні потоки можуть отримувати доступ до неї let greeting = "Hello"; // Функція `scope` створює потоки, що не будуть знищені до кінця своєї роботи // аргумент анонімної функції - об'єкт типу `Scope`, який і триматиме потоки std::thread::scope(|s| { for num in 0..10 { // `move` визначає захоплення за значенням s.spawn(move || { // `println!` - це макрос, що формує виведення за форматним рядком під час компіляції // Макроси в Rust структурні (як у Scheme), а не текстові (як у C). println!("{greeting} from thread number {num}"); }); } }); }
Українська спільнота Rust Редагувати
Існує та активно розвивається українська гілка Rust-спільноти. Метою спільноти є популяризація Rust в Україні та розвиток спільноти навколо нього, запуск або сприяння розвитку всеукраїнських менторських та освітніх програм, залучення проєктів на Rust та пов'язаних з ними інвестицій в Україну.
Створено підбірку навчальних матеріалів, завершується робота над перекладом підручника.[коли?]
Примітки Редагувати
- Announcing Rust 1.73.0 (англійська мова). 5 жовтень 2023. Процитовано 5 жовтень 2023.
- COPYRIGHT. Rust compiler source repository. Процитовано 17 грудня 2012.
- . 14 вересня 2010. Архів оригіналу за 20 липня 2020. Процитовано 17 квітня 2012.
- Future Tense. 29 квітня 2011. Архів оригіналу за 18 вересня 2012. Процитовано 17 квітня 2012. «At Mozilla Summit 2010, we launched Rust, a new programming language motivated by safety and concurrency for parallel hardware, the “manycore” future which is upon us.»
- Hello World!. Rust Foundation (англ.). 8 лютого 2020. оригіналу за 19 квітня 2022. Процитовано 4 червня 2022.
- Hoare, Graydon (7 червня 2014). . Reddit.com. Архів оригіналу за 14 липня 2016. Процитовано 4 лютого 2018.
- Hoare, Graydon (2 жовтня 2010). Rust Progress. Архів оригіналу за 18 вересня 2012. Процитовано 17 квітня 2012.
- Hoare, Graydon (20 квітня 2011). . Архів оригіналу за 20 липня 2011. Процитовано 17 квітня 2012. «After that last change fixing the logging scope context bug, looks like stage1/rustc builds. Just shy of midnight :)»
- . Архів оригіналу за 15 травня 2015. Процитовано 16 травня 2015.
- . Ars Technica. Архів оригіналу за 16 грудня 2016. Процитовано 24 жовтня 2015.
- . dou.ua. Архів оригіналу за 12 червня 2022. Процитовано 13 вересня 2022.
Посилання Редагувати
- Офіційний сайт
- Rust Language Wiki [ 10 лютого 2014 у Wayback Machine.]
- Електронний архів email листування Rust-dev [ 14 березня 2012 у Wayback Machine.]
- Основний репозиторій вихідних текстів та баг-трекер [ 3 вересня 2013 у Wayback Machine.]