Здравей, Rust
Въведение
6 октомври 2022
Административни неща
- Запишете се в сайта: https://fmi.rust-lang.bg/
- Записваме видео на екрана
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
$ cd hello
$ cargo run
Hello, world!
Cargo
Cargo
- Package manager
Cargo
- Package manager
- Task runner
Cargo
- Package manager
- Task runner
- Подобно на
mix
в elixir,bundler
в ruby,npm
/yarn
в node.js
Инсталация
Инсталация
- Rustup (https://rustup.rs/)
Инсталация
- Rustup (https://rustup.rs/)
$ rustup install stable
Инсталация
- Rustup (https://rustup.rs/)
$ rustup install stable
$ rustup doc
Инсталация
- Rustup (https://rustup.rs/)
$ rustup install stable
$ rustup doc
- https://2017.fmi.rust-lang.bg/topics/1
- Може би на уиндоус нещата са една идея по-лесни днешно време: https://www.reddit.com/r/rust/comments/v9uciv/rustup_on_windows_will_soon_give_the_option_to/
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: 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
let mut x = 5;
x += 1;
#[allow(unused_variables)] #[allow(unused_assignments)] fn main() { let mut x = 5; x += 1; }
Променливи
mutability
Това е различно от shadowing!
let x = 5;
let x = x + 1;
#[allow(unused_variables)] #[allow(unused_assignments)] fn main() { let x = 5; let x = x + 1; }
Основни типове
Целочислени типове
i8
,i16
,i32
,i64
,i128
,isize
u8
,u16
,u32
,u64
,u128
,usize
Основни типове
Целочислени типове
i8
,i16
,i32
,i64
,i128
,isize
u8
,u16
,u32
,u64
,u128
,usize
iN
- цяло (signed) число с размер N битаuN
- неотрицателно (unsigned) число с размер N бита
Основни типове
Целочислени типове
i8
,i16
,i32
,i64
,i128
,isize
u8
,u16
,u32
,u64
,u128
,usize
iN
- цяло (signed) число с размер N битаuN
- неотрицателно (unsigned) число с размер N битаisize
иusize
имат размер колкото машинната дума - 32 бита на 32 битов ОС и 64 бита на 64 битов ОС
Основни типове
Целочислени типове
i8
,i16
,i32
,i64
,i128
,isize
u8
,u16
,u32
,u64
,u128
,usize
iN
- цяло (signed) число с размер N битаuN
- неотрицателно (unsigned) число с размер N битаisize
иusize
имат размер колкото машинната дума - 32 бита на 32 битов ОС и 64 бита на 64 битов ОС
let x: u32 = 1337;
#![allow(unused_variables)] fn main() { let x: u32 = 1337; }
Основни типове
Целочислени типове (литерали)
Основни типове
Целочислени типове (литерали)
- Цяло число:
42
- Специфичен тип:
42u32
Основни типове
Целочислени типове (литерали)
- Цяло число:
42
- Специфичен тип:
42u32
- Големи числа:
133_587
1_000_000
Основни типове
Целочислени типове (литерали)
- Цяло число:
42
- Специфичен тип:
42u32
- Големи числа:
133_587
1_000_000
42_u32
Основни типове
Целочислени типове (литерали)
- Цяло число:
42
- Специфичен тип:
42u32
- Големи числа:
133_587
1_000_000
42_u32
1_0_0_0
Основни типове
Целочислени типове (литерали)
- Цяло число:
42
- Специфичен тип:
42u32
- Големи числа:
133_587
1_000_000
42_u32
1_0_0_0
1_____________________________________________________4
Основни типове
Целочислени типове (литерали)
- Цяло число:
42
- Специфичен тип:
42u32
- Големи числа:
133_587
1_000_000
42_u32
1_0_0_0
1_____________________________________________________4
let x: u32 = 1337;
let x = 1337_u32;
#![allow(unused_variables)] fn main() { let x: u32 = 1337; let x = 1337_u32; }
Основни типове
Целочислени типове (в различни бройни системи)
- Hex:
0xDEADBEEF
- Octal:
0o77
- Binary:
0b1010011010
Основни типове
Числа с плаваща запетая
f32
f64
- съответно 32 битов и 64 битов float
3.14
1.3_f64
Основни типове
Числа с плаваща запетая
f32
f64
- съответно 32 битов и 64 битов float
3.14
1.3_f64
let x: f64 = 3.14;
#![allow(unused_variables)] fn main() { let x: f64 = 3.14; }
Основни типове
Булеви стойности
bool
- стойности
true
иfalse
let x: bool = true;
#![allow(unused_variables)] fn main() { let x: bool = true; }
Основни типове
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 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; }
Специфики
Аритметични операции не могат да се прилагат върху различни типове
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; }
Специфики
Аритметични операции не могат да се прилагат върху различни типове
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
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);
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); }
Специфики
Няма оператори ++
и --
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 {
// ...
}
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
цикъла работи с итератори, за които ще говорим в бъдеща лекция
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
цикли.
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) * 4
add(5, 6)
Statements & Expressions
Израз (expression)
- нещо което може да се оцени
1
(2 + 3) * 4
add(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 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
Много от конструкциите на езика са изрази.
Блоковете са израз - стойността им е стойността на последния израз в блока
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); } #[allow(dead_code)] 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
на последния ред от тялото се счита за лоша практика
Анонимни функции (closures)
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!
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
println! macro
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); }
{:x}
и{:0}
placeholders и всевъзможни други (std::fmt
)
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
- Първо предизвикателство (не много предизвикателно): https://fmi.rust-lang.bg/challenges/1
Административни неща
- Инсталирайте си Rust: https://2017.fmi.rust-lang.bg/topics/1
- Елате в Discord канала: https://discord.gg/r9Wcazk
- Първо предизвикателство (не много предизвикателно): https://fmi.rust-lang.bg/challenges/1
- Fun fact: ако си качите снимка в сайта, ще получите 1 бонус точка