Здравей, Rust
Въведение
7 октомври 2020
Hello, world!
Защото винаги от там се почва:
fn main() {
println!("Hello, world!");
}
fn main() {
println!("Hello, world!");
}
Компилация
Можем да използваме компилатора на Rust - rustc
Компилация
Можем да използваме компилатора на Rust - rustc
$ rustc hello.rs
$ ./hello
Hello, world!
Компилация
Но, разбира се, има по-лесен начин
Компилация
Но, разбира се, има по-лесен начин
$ cargo new hello
$ cargo run
Hello, world!
Cargo
Cargo
- Package manager
Cargo
- Package manager
- Task runner
Cargo
- Package manager
- Task runner
- Подобно на
mixв elixir,bundlerв ruby,npmв node.js
Инсталация
Инсталация
Инсталация
Инсталация
- https://2017.fmi.rust-lang.bg/topics/1
- Rustup (https://rustup.rs/)
$ rustup install stable
Инсталация
- https://2017.fmi.rust-lang.bg/topics/1
- Rustup (https://rustup.rs/)
$ rustup install stable$ rustup doc
The Rust Book
Rust playpen
Променливи
Променливи се декларират с let
let NAME = VALUE;
let NAME: TYPE = VALUE;
let x = 5;
let y: i32 = 3;
#[allow(unused_variables)]
fn main() {
let x = 5;
let y: i32 = 3;
}
Променливи
Всяка променлива има тип, но можем да не пишем типа, ако е ясен от контекста
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`
}
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
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
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 по подразбиране
let x = 5;
x += 1;
Променливи
mutability
Променливите са immutable по подразбиране
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
let mut x = 5;
x += 1;
#[allow(unused_variables)]
#[allow(unused_assignments)]
fn main() {
let mut x = 5;
x += 1;
}
Основни типове
Целочислени типове
i8,i16,i32,i64,i128,isizeu8,u16,u32,u64,u128,usize
Основни типове
Целочислени типове
i8,i16,i32,i64,i128,isizeu8,u16,u32,u64,u128,usizeiN- цяло (signed) число с размер N битаuN- неотрицателно (unsigned) число с размер N бита
Основни типове
Целочислени типове
i8,i16,i32,i64,i128,isizeu8,u16,u32,u64,u128,usizeiN- цяло (signed) число с размер N битаuN- неотрицателно (unsigned) число с размер N битаisizeиusizeимат размер колкото машинната дума - 32 бита на 32 битов ОС и 64 бита на 64 битов ОС
Основни типове
Целочислени типове (литерали)
Основни типове
Целочислени типове (литерали)
- Цяло число:
42 - Специфичен тип:
42u32
Основни типове
Целочислени типове (литерали)
- Цяло число:
42 - Специфичен тип:
42u32 - Големи числа:
133_587 42_u32
Основни типове
Целочислени типове (литерали)
- Цяло число:
42 - Специфичен тип:
42u32 - Големи числа:
133_587 42_u321_0_0_0
Основни типове
Целочислени типове (литерали)
- Цяло число:
42 - Специфичен тип:
42u32 - Големи числа:
133_587 42_u321_0_0_01_____________________________________________________4
Основни типове
Целочислени типове (в различни бройни системи)
- Hex:
0xDEADBEEF - Octal:
0o77 - Binary:
0b1010011010
Основни типове
Числа с плаваща запетая
f32f64- съответно 32 битов и 64 битов float
3.141.3_f64
Основни типове
bool
bool- стойности
trueиfalse
Основни типове
unit
- тип
() - стойност
()
Основни типове
unit
- тип
() - стойност
() - тип с една единствена стойност
- големина 0 байта, не носи информация
- използва се за функции които не връщат стойност
- и на други места
Основни типове
unit
- тип
() - стойност
() - тип с една единствена стойност
- големина 0 байта, не носи информация
- използва се за функции които не връщат стойност
- и на други места
let x: () = ();
#![allow(unused_variables)]
fn main() {
let x: () = ();
}
Основни типове
Низове
str
Основни типове
Низове
str- utf8 низ
- ще му обърнем повече внимание в бъдеща лекция.
Основни типове
Низове
str- utf8 низ
- ще му обърнем повече внимание в бъдеща лекция.
let s = "Нещо друго";
#![allow(unused_variables)]
fn main() {
let s = "Нещо друго";
}
Основни типове
Низове
str- utf8 низ
- ще му обърнем повече внимание в бъдеща лекция.
let s = "Нещо друго";
#![allow(unused_variables)]
fn main() {
let s = "Нещо друго";
}
let s: &str = "Нещо друго";
#![allow(unused_variables)]
fn main() {
let s: &str = "Нещо друго";
}
Основни типове
Низове
str- utf8 низ
- ще му обърнем повече внимание в бъдеща лекция.
let s = "Нещо друго";
#![allow(unused_variables)]
fn main() {
let s = "Нещо друго";
}
let s: &str = "Нещо друго";
#![allow(unused_variables)]
fn main() {
let s: &str = "Нещо друго";
}
let s: &'static str = "Нещо друго";
#![allow(unused_variables)]
fn main() {
let s: &'static str = "Нещо друго";
}
Основни типове
Символи
char
Основни типове
Символи
char- unicode code point
- различно е от
u8 - ще му обърнем внимание заедно с низовете
Основни типове
Символи
char- unicode code point
- различно е от
u8 - ще му обърнем внимание заедно с низовете
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);
}
Основни типове
Масиви
[T; n]
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)
(A, B, C, ...)
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
| Length | Rust | C/C++ | ||
|---|---|---|---|---|
| Signed | Unsigned | Signed | Unsigned | |
| 8-bit | i8 | u8 | char | unsigned char |
| 16-bit | i16 | u16 | short | unsigned short |
| 32-bit | i32 | u32 | int | unsigned int |
| 64-bit | i64 | u64 | long long | unsigned long long |
| word | isize | usize | long | unsigned long / size_t |
| Length | Rust | C/C++ |
|---|---|---|
| 32-bit | f32 | float |
| 64-bit | f64 | double |
| Length | Rust | C++ |
|---|---|---|
| 8-bit | bool | bool |
| - | () | void |
Специфики
Няма автоматично конвертиране между различни числови типове
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 `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;
}
Специфики
Аритметични операции не могат да се прилагат върху различни типове
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 `std::ops::Sub<u8>` is not implemented for `u32`
#![allow(unused_variables)]
fn main() {
let x = 4_u32 - 1_u8;
}
Специфики
Аритметични операции не могат да се прилагат върху различни типове
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 `std::ops::Div<f32>` is not implemented for `f64`
#![allow(unused_variables)]
fn main() {
let y = 1.2_f64 / 0.8_f32;
}
Специфики
За конвертиране между типове се използва ключовата дума as
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)
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);
}
Специфики
Няма оператори ++ и --
x += 1;
x -= 1;
Коментари
Едноредов коментар
// 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 поддържа и блокови коментари
/*
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-клауза
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 цикъла работи с итератори, за които ще говорим в бъдеща лекция
for var in iterable {
// ...
}
#![allow(unused_variables)]
fn main() {
let iterable: &[()] = &[];
for var in iterable {
// ...
}
}
Отново няма скоби след for и скобите за блок { } са задължителни.
Control flow
Цикли
Също така има и while и loop цикли.
while bool_expression {
// ...
}
fn main() {
let bool_expression = false;
while bool_expression {
// ...
}
}
loop e същото като while true, но по-четимо.
loop {
// ...
}
fn main() {
loop {
// ...
}
}
Statements & Expressions
Израз (expression)
Statements & Expressions
Израз (expression)
- нещо което може да се оцени
Statements & Expressions
Израз (expression)
- нещо което може да се оцени
1
Statements & Expressions
Израз (expression)
- нещо което може да се оцени
1(2 + 3) * 4
Statements & Expressions
Израз (expression)
- нещо което може да се оцени
1(2 + 3) * 4add(5, 6)
Statements & Expressions
Израз (expression)
- нещо което може да се оцени
1(2 + 3) * 4add(5, 6)- (
add(5, 6);също е израз, със стойност()-- повече за това по-нататък)
Statements & Expressions
Твърдение (statement)
Statements & Expressions
Твърдение (statement)
- казва какво да се направи
Statements & Expressions
Твърдение (statement)
- казва какво да се направи
let x = 10;
Statements & Expressions
Твърдение (statement)
- казва какво да се направи
let x = 10;return 25;
Statements & Expressions
Твърдение (statement)
- казва какво да се направи
let x = 10;return 25;fn add(a: i32, b: i32) { a + b }
Statements & Expressions
Твърдение (statement)
- казва какво да се направи
let x = 10;return 25;fn add(a: i32, b: i32) { a + b }израз;
Statements & Expressions
Твърдение (statement)
Пример: можем да присвояваме стойността на израз на променлива с let, но не и стойността на твърдение (защото няма стойност)
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
Много от конструкциите на езика са изрази.
Блоковете са израз - стойността им е стойността на последния израз в блока
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 конструкцията е израз
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
};
}
По тази причина няма тернарен оператор
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 е израз
let x = loop {
break 5;
};
#[allow(unused_variables)]
fn main() {
let x = loop {
break 5;
};
}
Функции
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.");
}
Функции
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
}
Функции
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
}
- Задаването на типове на параметрите и резултата е задължително
Функции
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
}
- Задаването на типове на параметрите и резултата е задължително
- Върнатата стойност е стойността на последния израз в тялото на функцията
Функции
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);
}
- Не е нужно да пишем
-> ()за функции който не връщат резулат
Функции
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
}
- Ако искаме да излезем от функцията преди последния ред, може да използваме
return - Използване на
returnна последния ред от тялото се счита за лоша практика
Macros
- служат за генериране на код
- различават се от функциите по
!след името
Macros
- служат за генериране на код
- различават се от функциите по
!след името println!print!dbg!
println! macro
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
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
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);
}
- Принтиране на конзолата
{}placeholders
println! macro
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);
}
- Принтиране на конзолата
{:?}placeholders
dbg! macro
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);
}
Административни неща
- Инсталирайте си Rust: https://2017.fmi.rust-lang.bg/topics/1
Административни неща
- Инсталирайте си Rust: https://2017.fmi.rust-lang.bg/topics/1
- Елате в Discord канала: https://discord.gg/r9Wcazk
Административни неща
- Инсталирайте си Rust: https://2017.fmi.rust-lang.bg/topics/1
- Елате в Discord канала: https://discord.gg/r9Wcazk
- От другия път -- с парола! Вижте си секция "Табло" в сайта
Административни неща
- Инсталирайте си Rust: https://2017.fmi.rust-lang.bg/topics/1
- Елате в Discord канала: https://discord.gg/r9Wcazk
- От другия път -- с парола! Вижте си секция "Табло" в сайта
- Първо предизвикателство (не много предизвикателно): https://fmi.rust-lang.bg/challenges/1