Здравей, Rust

Въведение

6 октомври 2022

Административни неща

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 4
$ cargo new hello
$ cd hello
$ 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: consider making this binding mutable: `mut x` 6 | x += 1; | ^^^^^^ cannot assign twice to immutable variable For more information about this error, try `rustc --explain E0384`. error: could not compile `rust` due to previous error
#[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;
}

Променливи

mutability

Това е различно от shadowing!

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Булеви стойности

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

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

unit

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

unit

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

unit

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

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

Низове

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

Низове

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

Низове

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

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

Низове

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

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

Низове

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

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

Символи

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

Символи

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

Символи

1 2 3 4 5 6 7
let heart1: char = '❤';
let heart2: char = '\u{2764}';
let heart3: &str = "❤";

println!("{:?}", heart1);
println!("{:?}", heart2);
println!("{:?}", heart3);
'❤' '❤' "❤"
fn main() {
let heart1: char = '❤';
let heart2: char = '\u{2764}';
let heart3: &str = "❤";

println!("{:?}", heart1);
println!("{:?}", heart2);
println!("{:?}", heart3);
}

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

Масиви

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 3 4 5 6
let tuple: (i32, u32, bool) = (1, 2, false);
let unit: () = ();

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

println!("{}", tuple.0);
println!("{}", tuple.1);
println!("{}", tuple.2);
}

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

Сравнение със 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` | | | expected due to this | help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit | 5 | let y: u64 = x.try_into().unwrap(); | ++++++++++++++++++++ For more information about this error, try `rustc --explain E0308`. error: could not compile `rust` due to previous error
#![allow(unused_variables)]
fn main() {
let x: i32 = 1;
let y: u64 = x;
}

Специфики

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

1
let x = 4_u32 - 1_u8;
error[E0308]: mismatched types --> src/bin/main_8e5225b507b03e7c9f6c018e0cefb8bd8bc78341.rs:4:17 | 4 | let x = 4_u32 - 1_u8; | ^^^^ expected `u32`, found `u8` error[E0277]: cannot subtract `u8` from `u32` --> src/bin/main_8e5225b507b03e7c9f6c018e0cefb8bd8bc78341.rs:4:15 | 4 | let x = 4_u32 - 1_u8; | ^ no implementation for `u32 - u8` | = help: the trait `Sub<u8>` is not implemented for `u32` = help: the following other types implement trait `Sub<Rhs>`: <&'a f32 as Sub<f32>> <&'a f64 as Sub<f64>> <&'a i128 as Sub<i128>> <&'a i16 as Sub<i16>> <&'a i32 as Sub<i32>> <&'a i64 as Sub<i64>> <&'a i8 as Sub<i8>> <&'a isize as Sub<isize>> and 48 others Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. error: could not compile `rust` due to 2 previous errors
#![allow(unused_variables)]
fn main() {
let x = 4_u32 - 1_u8;
}

Специфики

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

1
let y = 1.2_f64 / 0.8_f32;
error[E0308]: mismatched types --> src/bin/main_f1878bdeb672a355ef5d23dbdfc01d0241278399.rs:4:19 | 4 | let y = 1.2_f64 / 0.8_f32; | ^^^^^^^ expected `f64`, found `f32` error[E0277]: cannot divide `f64` by `f32` --> src/bin/main_f1878bdeb672a355ef5d23dbdfc01d0241278399.rs:4:17 | 4 | let y = 1.2_f64 / 0.8_f32; | ^ no implementation for `f64 / f32` | = help: the trait `Div<f32>` is not implemented for `f64` = help: the following other types implement trait `Div<Rhs>`: <&'a f32 as Div<f32>> <&'a f64 as Div<f64>> <&'a i128 as Div<i128>> <&'a i16 as Div<i16>> <&'a i32 as Div<i32>> <&'a i64 as Div<i64>> <&'a i8 as Div<i8>> <&'a isize as Div<isize>> and 54 others Some errors have detailed explanations: E0277, E0308. For more information about an error, try `rustc --explain E0277`. error: could not compile `rust` due to 2 previous errors
#![allow(unused_variables)]
fn main() {
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);
error: this arithmetic operation will overflow --> src/bin/main_c02999f2504c2ca084dca6d96adc70ddb7bf1bae.rs:4:9 | 4 | let y = x + 1; // 💥 | ^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default error: could not compile `rust` due to previous error
#[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 8 9 10 11 12 13
if bool_expression {
    // ...
} else if another_bool_expression {
    // ...
} else {
    // ...
}

if 2 > 1 {
    println!("okay");
} else {
    println!("wait what");
}
fn main() {
let bool_expression = true;
let another_bool_expression = false;
if bool_expression {
    // ...
} else if another_bool_expression {
    // ...
} else {
    // ...
}

if 2 > 1 {
    println!("okay");
} else {
    println!("wait what");
}
}

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

Control flow

Цикли

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

1 2 3 4 5 6 7
for var in iterable {
    // ...
}

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

for n in [1, 2, 3] {
    println!("N: {}", n);
}
}

Отново няма скоби след 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 error: could not compile `rust` due to previous error
#![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);
}

#[allow(dead_code)]
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
}

Анонимни функции (closures)

1 2 3 4 5 6 7 8 9
fn add1(a: u32, b: u32) -> u32 {
    a + b
}

fn main() {
    let add2 = |a, b| { a + b };

    println!("add1: {}\nadd2: {}", add1(1, 2), add2(1, 2));
}
add1: 3 add2: 3
fn add1(a: u32, b: u32) -> u32 {
    a + b
}

fn main() {
    let add2 = |a, b| { a + b };

    println!("add1: {}\nadd2: {}", add1(1, 2), add2(1, 2));
}

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);
}

println! macro

1 2 3
let x = 255;
let y = 10;
println!("x = {:x} and y = {:04}", x, y);
x = ff and y = 0010
fn main() {
let x = 255;
let y = 10;
println!("x = {:x} and y = {:04}", 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);
}

Административни неща

Административни неща

Административни неща

Административни неща

Въпроси