learnxinyminutes-docs/uk/rust.md
2024-12-08 23:20:53 -07:00

13 KiB
Raw Blame History

contributors translators filename
P1start
http://p1start.github.io/
Volodymyr Korniichuk
https://github.com/ezhikus
learnrust-uk.rs

Rust - це мова програмування, що розрабляється спільнотою Mozilla Research Rust поєднує в собі низькорівневий контроль швидкодії з високорівневими інструментами забезпечення гарантій цілісності та безпеки.

Rust досягає своїх цілей без автоматичного збирання сміття і не вимагає наявності певного середовища виконання, що робить можливим пряму заміну бібліотек, написаних на мові С на бібліотеки, написані на Rust.

Перший реліз Rust (версія 0.1) вийшла в січні 2012 року і з тих пір оновлення виходили так часто, що загальною порадою розробникам було не чекати якоїсь стабільної версії, а використовувати нічні збірки компілятора.

15 травня 2015 року вийшла версія Rust 1.0. Для цієї версії була дана гарантія зворотної сумісності. Подальші нічні збірки покращили швидкість компіляції та деякі інші аспекти. На даний момент оновлення Rust виходять кожні 6 тижнів. Бета-версія Rust 1.1 вийшла одночасно з релізом Rust 1.0.

Не зважаючи на те, що Rust є відносно низькорівневою мовою програмування, в ній є деякі концепти, притаманні високорівневим мовам. Це робить Rust не лише швидким, але й досить зручним та ефективним інструментом розробки.

// Це коментар. Він починається в цьому рядку...
// і продовжується в цьому

/// Цей коментар включає в себе документацію і підтримує markdown.
/// # Приклади
///
/// ```
/// let five = 5
/// ```

///////////////
// 1. Основи //
///////////////

#[allow(dead_code)]
// Функції
// `i32` - це 32-бітний цілочислений знаковий тип даних
fn add2(x: i32, y: i32) -> i32 {
    // неявне повернення результату (в кінці рядку немає крапки з комою)
    x + y
}

#[allow(unused_variables)]
#[allow(unused_assignments)]
#[allow(dead_code)]
// Головна функція
fn main() {
    // Числа //

    // Незмінне число
    let x: i32 = 1;

    // суфікси для позначення цілого числа та числа з плаваючою змінною
    let y: i32 = 13i32;
    let f: f64 = 1.3f64;

    // Вивід типів
    // Як правило, Rust може самостійно визначити тип змінної, отож
    // ви можете не прописувати його явно
    // В даному документі типи явно прописані в багатьох місцях, це зроблено 
    // виключно в навчальних цілях. В реальному коді вивід типів спрацює 
    // в більшості випадків
    let implicit_x = 1;
    let implicit_f = 1.3;

    // арифметика
    let sum = x + y + 13;

    // Змінні
    let mut mutable = 1;
    mutable = 4;
    mutable += 2;

    // Строки //

    // Строкові літерали
    let x: &str = "Привіт, світ!";

    // Друк на екран
    println!("{} {}", f, x); // 1.3 Привіт, світ!

    // `String`  строка, що розміщується в "купі"
    let s: String = "hello world".to_string();

    // Строковий зріз - це незмінне відображення якоїсь строки (або її частини)
    // Зріз можна розглядати як константну пару покажчиків (на початок та кінець
    // якоїсь строки)
    let s_slice: &str = &s;

    println!("{} {}", s, s_slice); // Привіт, світ! Привіт, світ!

    // Вектори/масиви //

    // Масив фіксованого розміру
    let four_ints: [i32; 4] = [1, 2, 3, 4];

    // Масив змінного розміру (вектор)
    let mut vector: Vec<i32> = vec![1, 2, 3, 4];
    vector.push(5);

    // Зріз - незмінне відображення масиву
    // Це схоже на строковий зріз, але в даному випадку мова йде про вектори
    let slice: &[i32] = &vector;

    // Використовуйте `{:?}` щоб вивести щось в цілях відлагодження
    println!("{:?} {:?}", vector, slice); // [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]

    // Кортеж //

    // Кортеж - це набір фіксованого розміру, що включає значення кількох типів
    let x: (i32, &str, f64) = (1, "привіт", 3.4);

    // розбираємо кортеж "х" на окремі змінні "a", "b" та "с"
    let (a, b, c) = x;
    println!("{} {} {}", a, b, c); // 1 привіт 3.4

    // доступ по індексу
    println!("{}", x.1); // привіт

    //////////////
    // 2. Типи //
    //////////////

    // Структура
    struct Point {
        x: i32,
        y: i32,
    }

    let origin: Point = Point { x: 0, y: 0 };

    // Структура з безіменними полями, "кортежна структура"
    struct Point2(i32, i32);

    let origin2 = Point2(0, 0);

    // перелічуваний тип даних
    enum Direction {
        Left,
        Right,
        Up,
        Down,
    }

    let up = Direction::Up;

    // перелічуваний тип даних з полями
    enum OptionalI32 {
        AnI32(i32),
        Nothing,
    }

    let two: OptionalI32 = OptionalI32::AnI32(2);
    let nothing = OptionalI32::Nothing;

    // Узагальнене програмування //

    struct Foo<T> { bar: T }

    // Ось так стандартна бібліотека Rust оголошує `Option`
    enum Optional<T> {
        SomeVal(T),
        NoVal,
    }

    // Методи //

    impl<T> Foo<T> {
        // Методи приймають неявний параметр `self`
        fn get_bar(self) -> T {
            self.bar
        }
    }

    let a_foo = Foo { bar: 1 };
    println!("{}", a_foo.get_bar()); // 1

    // Типажі (в інших мовах програмування схожою сутністю є інтерфейси) //

    trait Frobnicate<T> {
        fn frobnicate(self) -> Option<T>;
    }

    impl<T> Frobnicate<T> for Foo<T> {
        fn frobnicate(self) -> Option<T> {
            Some(self.bar)
        }
    }

    let another_foo = Foo { bar: 1 };
    println!("{:?}", another_foo.frobnicate()); // Some(1)

    /////////////////////////
    // 3. Відповідність шаблону //
    /////////////////////////

    let foo = OptionalI32::AnI32(1);
    match foo {
        OptionalI32::AnI32(n) => println!("Це тип i32: {}", n),
        OptionalI32::Nothing  => println!("Це ніщо!"),
    }

    // Складніший приклад
    struct FooBar { x: i32, y: OptionalI32 }
    let bar = FooBar { x: 15, y: OptionalI32::AnI32(32) };

    match bar {
        FooBar { x: 0, y: OptionalI32::AnI32(0) } =>
            println!("Числа рівні нулю!"),
        FooBar { x: n, y: OptionalI32::AnI32(m) } if n == m =>
            println!("Числа однакові"),
        FooBar { x: n, y: OptionalI32::AnI32(m) } =>
            println!("Числа різні: {} {}", n, m),
        FooBar { x: _, y: OptionalI32::Nothing } =>
            println!("Друге число - ніщо!"),
    }

    /////////////////////
    // 4. Потік керування //
    /////////////////////

    // Цикл `for` 
    let array = [1, 2, 3];
    for i in array {
        println!("{}", i);
    }

    // Діапазони
    for i in 0u32..10 {
        print!("{} ", i);
    }
    println!("");
    // друкує `0 1 2 3 4 5 6 7 8 9 `

    // `if`
    if 1 == 1 {
        println!("Математика працює!");
    } else {
        println!("Ой, лишенько...");
    }

    // `if` як вираз
    let value = if true {
        "добре"
    } else {
        "погано"
    };

    // Цикл `while`
    while 1 == 1 {
        println!("Всесвіт функціонує стабільно.");
        // Вираз break перериває цикл
        break
    }

    // Нескінченний цикл
    loop {
        println!("Привіт!");
        // Вираз break перериває цикл
        break
    }

    /////////////////////////////////
    // 5. Вказівники і безпека пам'яті //
    /////////////////////////////////

    // Володіючий вказівник - тільки хтось один може "володіти" вказівником в 
    // будь-який момент. Це означає, що коли "Box" вийде за межі області 
    // видимості - його можна безпечно звільнити
    let mut mine: Box<i32> = Box::new(3);
    *mine = 5; // розіменування `mine` з присвоєнням йому нового значення
    // `now_its_mine` перебирає на себе володіння над `mine`. Іншими словами, 
    // `mine` переміщується.
    let mut now_its_mine = mine;
    *now_its_mine += 2;

    println!("{}", now_its_mine); // 7
    // println!("{}", mine); // цей код не скомпілюється, оскільки тепер 
    // покажчиком на дані володіє `now_its_mine`

    // Посилання  незмінний вказівник на дані
    // При створенні посилання на якесь значення, ми говоримо, що значення 
    // було "запозичене". Поки значення є запозиченим - воно не може бути 
    // змінене або переміщене. Запозичення пропадає, як тільки стається вихід з 
    // області видимості, де було створене посилання
    let mut var = 4;
    var = 3;
    let ref_var: &i32 = &var;

    println!("{}", var); // На відміну від `mine`, `var` можна використати
    println!("{}", *ref_var);
    // var = 5; // цей код не скомпілюється, оскільки `var` зараз є запозиченим
    // *ref_var = 6; // цей код також не зкомпілюється, оскільки `ref_var` 
    // є незмінним посиланням

    // Змінне посилання
    // Значення можна запозичити з можливістю зміни. У цьому випадку доступ до 
    // оригінального значення втрачається.
    let mut var2 = 4;
    let ref_var2: &mut i32 = &mut var2;
    *ref_var2 += 2;    // '*' використовується для доступу до змінного посилання

    println!("{}", *ref_var2); // 6 , // при заміні на var2 код не зкомпілюється
    // ref_var2 має тип &mut i32, отож зберігає посилання на i32, а не  значення
    // var2 = 2; // цей рядок не зкомпілюється, оскільки `var2` є запозиченим.
}

Матеріали для самовдосконалення

В даному матеріалі ми оглянули лише основи Rust. Більше матеріалу ви можете знайти на сайті The Rust Programming Language Також існує Reddit-розділ /r/rust. Люди на каналі irc.mozilla.org також завжди раді допомогти новачкам.

Ви можете спробувати можливості Rust за допомогою онлайн-компілятора на сторінці Rust Playground або Rust website.