Rust (мова програмування)
Rust (укр. Раст, дос. «Іржа») — сучасна багатопарадигмова мова програмування загального призначення. Мова має сильну (строгу) типізацію і зосереджена на безпечній роботі з пам'яттю та забезпеченні високої рівночасности виконання задач (можливість породжувати тисячі й навіть мільйони підпроцесів). Початковий код проєкту поширюється під ліцензією MIT. ІсторіяРобота над мовою була розпочата працівником Mozilla Ґрейдоном Гоаром 2006 року як особистий проєкт. 2009[4] до розроблення залучилася Mozilla, а 2010 року мова була офіційно представлена на Mozilla Summit 2010[5]. З 2021, після скорочень у Mozilla, розроблення здійснює окремий фонд Rust Foundation[6]. Мову названо за назвою родини грибів іржа.[7] 2010 року розроблення мови було переведено з попередньої версії компілятора, яка була написана мовою OCaml, на компілятор, який написаний безпосередньо на Rust, з використанням LLVM як бекенду[8]. 2011 року новий компілятор успішно скомпілював сам себе[9]. Перший стабільний випуск мови Rust 1.0 відбувся 15 травня 2015[10] після п'яти років розроблення, він ознаменував повну стабілізацію програмних інтерфейсів усіх бібліотек і мовних конструкцій. У ході підготовування гілки Rust 1.0 програмні інтерфейси та можливості мови піддалися значному огляду, після якого типово залишені лише повністю готові до застосування можливості, упровадження яких не змінюватиметься надалі. Усі інші особливості переведені в розряд експериментальних і винесені зі стандартного постачання. Опоруч Mozilla Research розвиває експериментальний браузерний рушій Servo, написаний мовою Rust з підтримкою багатопотокового рендерингу вебсторінок і розрівнобіжненням операцій з DOM, а компанія Samsung займається його портуванням на Android та ARM процесори[11]. ОглядЗа структурою, мова Rust нагадує C++, але істотно відрізняється в деяких дрібницях реалізації синтаксису та семантики, а також зосередженням на блочну організацію структури коду, яка дозволяє реалізувати завдання, подібно до легковагих співпрограм. Автоматичне керування пам'яттю позбавляє розробника потреби маніпулювання вказівниками й захищає від проблем, що виникають через низькорівневу роботу з пам'яттю, таких як звернення до ділянки пам'яті після її звільнення, розіменовування нульових вказівників, вихід за межі буфера тощо. Rust підтримує суміш імперативних, процедурних і об'єктно-орієнтованих методів з такими парадигмами, як функційне програмування і модель акторів, а також узагальнене програмування і метапрограмування, у статичних і динамічних стилях. Мова сфокусована на безпечній роботі з пам'яттю та надає засоби для досягнення високого паралелізму виконання завдань, при цьому обходячись без використання збирача сміття та runtime (runtime зводиться до базової ініціалізації та супроводу стандартної бібліотеки). Безпечна робота з пам'яттю забезпечується в Rust під час компіляції через перевірку посилань, відстеження володіння об'єктами, облік часу життя об'єктів (області видимості) та оцінку коректності доступу до пам'яті під час виконання коду. Rust також надає засоби для захисту від цілих переповнень, вимагає обов'язкової ініціалізації значень змінних перед використанням, краще обробляє помилки в стандартній бібліотеці, застосовує концепцію незмінності посилань і змінних за умовчанням, пропонує сильну статичну типізацію для мінімізації логічних помилок. Для поширення бібліотек, забезпечення збирання та управління залежностями проектом розвивається пакетний менеджер Cargo. Для розміщення бібліотеки підтримується репозиторій crates.io. Синтаксис та особливостіОсобливості мовиОсновні можливості мови:
Володіння і контролер позичаньВиразною особливістю Rust є система володіння даними, забезпечена частиною компілятора, що зветься контролером позичань (англ. borrow checker). Позичанням зветься створення посилання. Правила володіння і позичання:
Контролер позичань являє собою чи не найскладніше, з чим доводиться стикатися новим розробникам Rust. Він забороняє дуже багато практик, до яких можна легко звикнути в інших мовах програмування; натомість він захищає програміста від багатьох поширених в інших мовах помилок, таких як суперечності в даних (одна частина програми не може їх змінити, коли на них є посилання з іншої частини), зміна ітерованого об'єкта під час ітерації, гонитва даних і т. д. ОзнакиОзнаки (також іноді трейти, типажі, англ. traits) є однією з виразних особливостей Rust. Ознаки загалом нагадують інтерфейси в мовах програмування, що підтримують ООП, і позначають спільну поведінку різних типів. Типи данихПрості (примітивні) типи
Складені типи
Типи зі стандартної бібліотеки
Вказівники
Задані користувачем типи
ПрикладиНаведені нижче приклади є робочими під час збирання за допомогою стабільної версії компілятора 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}");
});
}
});
}
Примітки
Посилання
|