Здравей, Rust

Въведение

10 октомври 2019

Hello, world!

Защото винаги от там се почва:

1 2 3
fn main() {
    println!("Hello, world!");
}
fn main() {
    println!("Hello, world!");
}

Компилация

Можем да използваме компилатора на Rust - rustc

Компилация

Можем да използваме компилатора на Rust - rustc

1 2 3
$ rustc hello.rs
$ ./hello
Hello, world!

Компилация

Но, разбира се, има по-лесен начин

Компилация

Но, разбира се, има по-лесен начин

1 2 3
$ cargo new hello --bin
$ cargo run
Hello, world!

Cargo

Cargo

Cargo

Cargo

Инсталация

Инсталация

Инсталация

Инсталация

Инсталация

The Rust Book

https://doc.rust-lang.org/stable/book/

Rust playpen

https://play.rust-lang.org/

Променливи

Променливи се декларират с let

let NAME = VALUE;
let NAME: TYPE = VALUE;

1 2
let x = 5;
let y: i32 = 3;
#[allow(unused_variables)]
fn main() {
let x = 5;
let y: i32 = 3;
}

Променливи

Всяка променлива има тип, но можем да не пишем типа, ако е ясен от контекста

1 2
let x: i32 = 5;
let y = x;      // типа на `y` е `i32`, защото `x` e `i32`
#[allow(unused_variables)]
fn main() {
let x: i32 = 5;
let y = x;      // типа на `y` е `i32`, защото `x` e `i32`
}
1 2
let x = 5;      // типа на `x` е `i32`, защото `y` e `i32`
let y: i32 = x;
#[allow(unused_variables)]
fn main() {
let x = 5;      // типа на `x` е `i32`, защото `y` e `i32`
let y: i32 = x;
}

Променливи

shadowing

1 2 3
let x = 10;
let x = x + 10;
let x = x * 3;
#[allow(unused_variables)]
fn main() {
let x = 10;
let x = x + 10;
let x = x * 3;
}

Променливи

shadowing

1 2 3
let x1 = 10;
let x2 = x1 + 10;
let x3 = x2 * 3;
#[allow(unused_variables)]
fn main() {
let x1 = 10;
let x2 = x1 + 10;
let x3 = x2 * 3;
}

Променливи

mutability

Променливите са immutable по подразбиране

1 2
let x = 5;
x += 1;

Променливи

mutability

Променливите са immutable по подразбиране

1 2
let x = 5;
x += 1;
error[E0384]: cannot assign twice to immutable variable `x` --> src/bin/main_7db00a1a92dd466b5d0d2e943c3247d86695e529.rs:6:1 | 5 | let x = 5; | - | | | first assignment to `x` | help: make this binding mutable: `mut x` 6 | x += 1; | ^^^^^^ cannot assign twice to immutable variable
#[allow(unused_variables)]
#[allow(unused_assignments)]
fn main() {
let x = 5;
x += 1;
}

Променливи

mutability

За да се направи mutable се използва ключовата дума mut

1 2
let mut x = 5;
x += 1;
#[allow(unused_variables)]
#[allow(unused_assignments)]
fn main() {
let mut x = 5;
x += 1;
}

Основни типове

Целочислени типове

Основни типове

Целочислени типове

Основни типове

Целочислени типове

Основни типове

Целочислени типове

Основни типове

Целочислени типове

Основни типове

Целочислени типове (литерали)

Основни типове

Целочислени типове (литерали)

Основни типове

Целочислени типове (литерали)

Основни типове

Целочислени типове (литерали)

Основни типове

Целочислени типове (литерали)

Основни типове

Целочислени типове (литерали)

Основни типове

Целочислени типове (литерали)

Основни типове

Целочислени типове (в различни бройни системи)

Основни типове

Целочислени типове (в различни бройни системи)

Основни типове

Целочислени типове (в различни бройни системи)

Основни типове

Целочислени типове (в различни бройни системи)

Основни типове

Числа с плаваща запетая

Основни типове

Числа с плаваща запетая

Основни типове

Числа с плаваща запетая

Основни типове

bool

Основни типове

bool

Основни типове

bool

Основни типове

unit

Основни типове

unit

Основни типове

unit

Основни типове

unit

Основни типове

unit

1
let x: () = ();
#![allow(unused_variables)]
fn main() {
let x: () = ();
}

Основни типове

Низове

Основни типове

Низове

Основни типове

Низове

Основни типове

Низове

1
let s: &str = "Нещо друго";
#![allow(unused_variables)]
fn main() {
let s: &str = "Нещо друго";
}

Основни типове

Символи

Основни типове

Символи

Основни типове

Символи

Основни типове

Символи

1
let love: char = '❤';
#![allow(unused_variables)]
fn main() {
let love: char = '❤';
}

Основни типове

Масиви

1 2 3 4 5 6
let arr: [i32; 3] = [1, 2, 3];

let nested: [[i32; 3]; 2] = [
    [1, 2, 3],
    [4, 5, 6],
];
#![allow(unused_variables)]
fn main() {
let arr: [i32; 3] = [1, 2, 3];

let nested: [[i32; 3]; 2] = [
    [1, 2, 3],
    [4, 5, 6],
];
}

Основни типове

Кортежи (tuples)

1 2
let tuple: (i32, u32, bool) = (1, 2, false);
let unit: () = ();
#![allow(unused_variables)]
fn main() {
let tuple: (i32, u32, bool) = (1, 2, false);
let unit: () = ();
}

Основни типове

Сравнение със C

LengthRustC/C++
SignedUnsignedSignedUnsigned
8-biti8u8charunsigned char
16-biti16u16shortunsigned short
32-biti32u32intunsigned int
64-biti64u64long longunsigned long long
wordisizeusizelongunsigned long / size_t
Length Rust C/C++
32-bit f32 float
64-bit f64 double
Length Rust C++
8-bit bool bool
- () void

Специфики

Няма автоматично конвертиране между различни числови типове

1 2
let x: i32 = 1;
let y: u64 = x;
error[E0308]: mismatched types --> src/bin/main_8b638dfa209c175f12a85c93aaa5a902798b2434.rs:5:14 | 5 | let y: u64 = x; | ^ expected u64, found i32 help: you can convert an `i32` to `u64` and panic if the converted value wouldn't fit | 5 | let y: u64 = x.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^
#![allow(unused_variables)]
fn main() {
let x: i32 = 1;
let y: u64 = x;
}

Специфики

Аритметични операции не могат да се прилагат върху различни типове

1 2
let x = 4_u32 - 1_u8;
let y = 1.2_f64 / 0.8_f32;
error[E0308]: mismatched types --> src/bin/main_f41a9b3fe3295e5d1e8f7992bd3bb3605ce8d48d.rs:4:17 | 4 | let x = 4_u32 - 1_u8; | ^^^^ expected u32, found u8 error[E0277]: cannot subtract `u8` from `u32` --> src/bin/main_f41a9b3fe3295e5d1e8f7992bd3bb3605ce8d48d.rs:4:15 | 4 | let x = 4_u32 - 1_u8; | ^ no implementation for `u32 - u8` | = help: the trait `std::ops::Sub<u8>` is not implemented for `u32` error[E0308]: mismatched types --> src/bin/main_f41a9b3fe3295e5d1e8f7992bd3bb3605ce8d48d.rs:5:19 | 5 | let y = 1.2_f64 / 0.8_f32; | ^^^^^^^ expected f64, found f32 error[E0277]: cannot divide `f64` by `f32` --> src/bin/main_f41a9b3fe3295e5d1e8f7992bd3bb3605ce8d48d.rs:5:17 | 5 | let y = 1.2_f64 / 0.8_f32; | ^ no implementation for `f64 / f32` | = help: the trait `std::ops::Div<f32>` is not implemented for `f64`
#![allow(unused_variables)]
fn main() {
let x = 4_u32 - 1_u8;
let y = 1.2_f64 / 0.8_f32;
}

Специфики

За конвертиране между типове се използва ключовата дума as

1 2 3 4 5
let one = true as u8;
let two_hundred = -56_i8 as u8;
let three = 3.14 as u32;

println!("one: {}\ntwo_hundred: {}\nthree: {}", one, two_hundred, three);
one: 1 two_hundred: 200 three: 3
#[allow(unused_variables)]
fn main() {
let one = true as u8;
let two_hundred = -56_i8 as u8;
let three = 3.14 as u32;

println!("one: {}\ntwo_hundred: {}\nthree: {}", one, two_hundred, three);
}

Специфики

В режим debug, аритметични операции хвърлят грешка при препълванe (integer overflow / underflow)

1 2 3
let x = 255_u8;
let y = x + 1;                // 💥
println!("{}", y);
thread 'main' panicked at 'attempt to add with overflow', src/bin/main_c02999f2504c2ca084dca6d96adc70ddb7bf1bae.rs:4:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
#[allow(unused_variables)]
fn main() {
let x = 255_u8;
let y = x + 1;                // 💥
println!("{}", y);
}

Специфики

Няма оператори ++ и --

1 2
x += 1;
x -= 1;

Коментари

Едноредов коментар

1 2 3
// So we’re doing something complicated here, long enough that we need
// multiple lines of comments to do it! Whew! Hopefully, this comment will
// explain what’s going on.

Rust поддържа и блокови коментари

1 2 3 4 5
/*
So we’re doing something complicated here, long enough that we need
multiple lines of comments to do it! Whew! Hopefully, this comment will
explain what’s going on.
*/

Control flow

if-клаузи

Синтаксис на if-клауза

1 2 3 4 5 6 7
if bool_expression {
    // ...
} else if another_bool_expression {
    // ...
} else {
    // ...
}
fn main() {
let bool_expression = true;
let another_bool_expression = false;
if bool_expression {
    // ...
} else if another_bool_expression {
    // ...
} else {
    // ...
}
}

Забележете, че няма скоби около условието и скобите за блок { } са задължителни.

Control flow

Цикли

for цикъла работи с итератори, за които ще говорим в бъдеща лекция

1 2 3
for var in iterable {
    // ...
}
#![allow(unused_variables)]
fn main() {
let iterable: &[()] = &[];
for var in iterable {
    // ...
}
}

Отново няма скоби след for и скобите за блок { } са задължителни.

Control flow

Цикли

Също така има и while и loop цикли.

1 2 3
while bool_expression {
    // ...
}
fn main() {
let bool_expression = false;
while bool_expression {
    // ...
}
}

loop e същото като while true, но по-четимо.

1 2 3
loop {
    // ...
}
fn main() {
loop {
    // ...
}
}

Statements & Expressions

Израз (expression)

Statements & Expressions

Израз (expression)

Statements & Expressions

Израз (expression)

Statements & Expressions

Израз (expression)

Statements & Expressions

Израз (expression)

Statements & Expressions

Израз (expression)

Statements & Expressions

Твърдение (statement)

Statements & Expressions

Твърдение (statement)

Statements & Expressions

Твърдение (statement)

Statements & Expressions

Твърдение (statement)

Statements & Expressions

Твърдение (statement)

Statements & Expressions

Твърдение (statement)

Statements & Expressions

Твърдение (statement)

Пример: можем да присвояваме стойността на израз на променлива с let, но не и стойността на твърдение (защото няма стойност)

1
let x = (fn add(a: i32, b: i32) { a + b });
error: expected expression, found keyword `fn` --> src/bin/main_97ba87efcfac218791b39b5b3ee18a18037e022c.rs:4:10 | 4 | let x = (fn add(a: i32, b: i32) { a + b }); | ^^ expected expression
#![allow(unused_variables)]
#![allow(unused_parens)]
fn main() {
let x = (fn add(a: i32, b: i32) { a + b });
}

Statements & Expressions

Много от констукциите на езика са изрази.

Блоковете са израз - стойността им е стойността на последния израз в блока

1 2 3 4 5 6 7 8 9
fn main() {
    let x = {
        let a = 1;
        let b = 2;
        a + b
    };

    println!("x = {}", x);
}
x = 3
fn main() {
    let x = {
        let a = 1;
        let b = 2;
        a + b
    };

    println!("x = {}", x);
}

Statements & Expressions

if-else конструкцията е израз

1 2 3 4 5
let bigger = if a > b {
    a
} else {
    b
};
#[allow(unused_variables)]
fn main() {
let a = 1; let b = 2;
let bigger = if a > b {
    a
} else {
    b
};
}

По тази причина няма тернарен оператор

1
let bigger = if a > b { a } else { b };
#[allow(unused_variables)]
fn main() {
let a = 1; let b = 2;
let bigger = if a > b { a } else { b };
}

Statements & Expressions

loop е израз

1 2 3
let x = loop {
    break 5;
};
#[allow(unused_variables)]
fn main() {
let x = loop {
    break 5;
};
}

Функции

1 2 3 4 5 6 7 8
fn main() {
    println!("Hello, world!");
    another_function();
}

fn another_function() {
    println!("Another function.");
}
Hello, world! Another function.
fn main() {
    println!("Hello, world!");
    another_function();
}

fn another_function() {
    println!("Another function.");
}

Функции

1 2 3 4
fn add(a: u32, b: u32) -> u32 {
    // note no semicolon
    a + b
}
fn main() {}
#[allow(dead_code)]
fn add(a: u32, b: u32) -> u32 {
    // note no semicolon
    a + b
}

Функции

1 2 3 4
fn add(a: u32, b: u32) -> u32 {
    // note no semicolon
    a + b
}
fn main() {}
#[allow(dead_code)]
fn add(a: u32, b: u32) -> u32 {
    // note no semicolon
    a + b
}

Функции

1 2 3 4
fn add(a: u32, b: u32) -> u32 {
    // note no semicolon
    a + b
}
fn main() {}
#[allow(dead_code)]
fn add(a: u32, b: u32) -> u32 {
    // note no semicolon
    a + b
}

Функции

1 2 3 4 5 6 7
fn print_a(a: u32) {
    println!("{}", a);
}

fn print_b(b: u32) -> () {
    println!("{}", b);
}
fn main() {}
#[allow(dead_code)]
fn print_a(a: u32) {
    println!("{}", a);
}

fn print_b(b: u32) -> () {
    println!("{}", b);
}

Функции

1 2 3 4 5 6 7
fn good_a(a: u32, a_is_bad: bool) -> u32 {
    if a_is_bad {
        return 0;
    }

    a
}
fn main() {}
#[allow(dead_code)]
fn good_a(a: u32, a_is_bad: bool) -> u32 {
    if a_is_bad {
        return 0;
    }

    a
}

Macros

Macros

Macros

Macros

Macros

println! macro

1 2 3
let x = 5;
let y = "десет";
println!("x = {} and y = {}", x, y);
x = 5 and y = десет
fn main() {
let x = 5;
let y = "десет";
println!("x = {} and y = {}", x, y);
}

println! macro

1 2 3
let x = 5;
let y = "десет";
println!("x = {} and y = {}", x, y);
x = 5 and y = десет
fn main() {
let x = 5;
let y = "десет";
println!("x = {} and y = {}", x, y);
}

println! macro

1 2 3
let x = 5;
let y = "десет";
println!("x = {} and y = {}", x, y);
x = 5 and y = десет
fn main() {
let x = 5;
let y = "десет";
println!("x = {} and y = {}", x, y);
}

println! macro

1 2 3
let x = 5;
let y = "десет";
println!("x = {:?} and y = {:?}", x, y);
x = 5 and y = "десет"
fn main() {
let x = 5;
let y = "десет";
println!("x = {:?} and y = {:?}", x, y);
}

dbg! macro

1 2 3 4 5
let x = 5;
let y = "десет";

dbg!(x);
dbg!(y);
[src/bin/main_72fe3d84fb206495b3ff0c4f73c4dc2f69e38ea2.rs:5] x = 5 [src/bin/main_72fe3d84fb206495b3ff0c4f73c4dc2f69e38ea2.rs:6] y = "десет"
fn main() {
let x = 5;
let y = "десет";

dbg!(x);
dbg!(y);
}

Въпроси