У Rust, коли ми даємо значенню імʼя, це називається звʼязуванням. Звʼязування незмінні, якщо їх не оголосити з ключовим словом mut. Оскільки Rust належить до статично типізованих мов, кожне звʼязування має тип, відомий під час компіляції.
Звʼязування найчастіше визначають за допомогою ключового слова let. Вказувати тип звʼязування необовʼязково для більшості звʼязувань, бо виведення типів у Rust зазвичай може визначити тип на основі їхнього значення. Звʼязування має такий вигляд:
// Automatically inferred type
let fingers = 10;
Функції належать до елементів. Якщо звʼязування зазвичай указують на конкретне значення, то елементи вказують на одиницю організації коду, найчастіше функцію або модуль, яка доступна протягом усього часу життя програми. Функція автоматично повертає результат свого останнього виразу. Функція може мати 0 або більше параметрів, тобто звʼязувань, час життя яких обмежено викликом функції.
Виведення типів теоретично можливе і для функцій, але його вимкнено як навмисне рішення в дизайні мови. Хоча це означає, що під час написання коду нам доведеться витратити трохи більше часу, щоб точно вказати типи вхідних і вихідних даних функції, зате ми заощаджуємо час під час читання коду, адже всі типи вхідних і вихідних даних визначено явно.
fn add(x: i32, y: i32) -> i32 {
x + y
}
Щоб викликати функцію, ми вказуємо її назву, а потім ставимо дужки. Якщо функція потребує параметрів, для кожного з них у дужках потрібно вказати аргумент.
let five = add(2, 3);
Якщо тип звʼязування неможливо вивести, компілятор повідомить про помилку. Щоб це виправити, додамо до звʼязування явну анотацію типу.
// Explicit type annotation
let fingers: i32 = 10;
Елементи Rust можна використовувати до або після того, як їх визначено, бо вони мають статичний час життя. Звʼязування ж можна використовувати лише після того, як їх визначено. Використання звʼязування до його визначення спричиняє помилку компіляції.
fn main() {
// `fn add` hasn't yet been defined, but that's perfectly ok
dbg!(add(3, 4));
}
fn add(x: i32, y: i32) -> i32 {
x + y
}
// this won't compile; `a` is used before its binding is defined
let b = a;
let a = x + y;
Rust використовує фігурні дужки ({}) для визначення області видимості. Звʼязування, визначене в межах області видимості, не може вийти з неї.
let a = 1;
dbg!(a); // 1
{
// Here, we re-bind `a` to a new value, which is still immutable.
// This technique is called _shadowing_. The new binding is constrained to
// this anonymous scope. Outside this scope, the previous binding still
// applies.
let a = 2;
let b = 3;
dbg!(a, b); // 2, 3
}
// can't use `b` anymore because it is out of scope
// dbg!(b);
// The shadowed `a` in the inner scope above has fallen out of scope,
// leaving us with our original binding.
dbg!(a); // 1
Елементи Rust часто організовують у модулі. Кожен крейт неявно є модулем, але може визначати внутрішні підмодулі довільної глибини. Модуль обʼєднує споріднену функціональність і визначається за допомогою ключового слова mod.
mod calc_i32 {
fn add(a: i32, b: i32) -> i32 { a + b }
fn sub(a: i32, b: i32) -> i32 { a - b }
fn mul(a: i32, b: i32) -> i32 { a * b }
fn div(a: i32, b: i32) -> i32 { a / b }
}
Rust підтримує два типи коментарів. Ключове слово // позначає однорядковий коментар; усе, що йде після нього до кінця рядка, ігнорується. Ключові слова /* і */ позначають багаторядковий коментар; усе між цими двома ключовими словами ігнорується. Вважається ідіоматичним і хорошою практикою надавати перевагу однорядковим коментарям.
Rust також підтримує doc-коментарі, які потрапляють у згенеровану документацію, створену командою cargo doc. Зовнішні doc-коментарі утворюють за допомогою ключового слова ///, яке діє так само, як ключове слово //. Вони застосовуються до елемента, що йде після них, наприклад до функції:
/// The `add` function produces the sum of its arguments.
fn add(x: i32, y: i32) -> i32 { x + y }
Внутрішні doc-коментарі утворюють за допомогою ключового слова //!, яке діє так само, як ключове слово //. Вони застосовуються до елемента, який їх містить, наприклад до модуля:
mod my_cool_module {
//! This module is the bee's knees.
}
Doc-коментарі можуть мати довільну довжину й містити markdown, який перетворюється на згенеровану документацію.
У цій вправі ми напишемо трохи коду, який допоможе приготувати чудову лазанью з улюбленої кулінарної книги.
На нас чекають чотири завдання, усі повʼязані з часом, витраченим на приготування лазаньї.
Визначте звʼязування expected_minutes_in_oven, щоб перевірити, скільки хвилин лазанья має бути в печі. Згідно з кулінарною книгою, очікуваний час запікання в хвилинах становить 40:
expected_minutes_in_oven()
// Returns: 40
Визначте функцію remaining_minutes_in_oven, яка приймає як параметр фактичну кількість хвилин, які лазанья вже провела в печі, і повертає, скільки хвилин їй ще залишилося там провести, виходячи з очікуваного часу запікання в хвилинах із попереднього завдання.
remaining_minutes_in_oven(30)
// Returns: 10
Визначте функцію preparation_time_in_minutes, яка приймає як параметр кількість шарів, які ми додали до лазаньї, і повертає, скільки хвилин ми витратили на її підготовку, вважаючи, що на кожен шар іде 2 хвилини.
preparation_time_in_minutes(2)
// Returns: 4
Визначте функцію elapsed_time_in_minutes, яка приймає два параметри: перший параметр - кількість шарів, які ми додали до лазаньї, а другий - кількість хвилин, які лазанья вже провела в печі. Функція має повертати, скільки хвилин ми витратили на приготування лазаньї, тобто суму часу підготовки в хвилинах і часу в хвилинах, який лазанья на цей момент провела в печі.
elapsed_time_in_minutes(3, 20)
// Returns: 26