Изброени типове и съпоставяне на образци
16 октомври 2018
Административни неща
Административни неща
- Първо домашно идва тоя четвъртък!
Административни неща
- Първо домашно идва тоя четвъртък!
- Ако не сте се регистрирали във https://fmi.rust-lang.bg, ще се наложи!
Преговор
Преговор
String
и&str
Преговор
String
и&str
Vec<T>
и&[T]
Преговор
String
и&str
Vec<T>
и&[T]
- Структури (асоциирани функции, методи)
Преговор
String
и&str
Vec<T>
и&[T]
- Структури (асоциирани функции, методи)
self
,&self
,&mut self
Преговор
String
и&str
Vec<T>
и&[T]
- Структури (асоциирани функции, методи)
self
,&self
,&mut self
- Организация на кода в модули
Преговор
String
и&str
Vec<T>
и&[T]
- Структури (асоциирани функции, методи)
self
,&self
,&mut self
- Организация на кода в модули
- Видимост (
pub
за типове, полета, функции)
Enums
enum IpAddrKind {
V4,
V6,
}
Enums
Инстанциране
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
Enums
Параметър
fn route(ip_type: IpAddrKind) { }
route(IpAddrKind::V4);
route(IpAddrKind::V6);
Enums
Данни
struct IpAddr {
kind: IpAddrKind,
address: String,
}
let home = IpAddr {
kind: IpAddrKind::V4,
address: String::from("127.0.0.1"),
};
let loopback = IpAddr {
kind: IpAddrKind::V6,
address: String::from("::1"),
};
Enums
Данни
По-удобен и четим начин
enum IpAddr {
V4(String),
V6(String),
}
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
Enums
Данни
Може да спестим памет като знаем че IPv4
използва стойности от 0-255
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
Enums
Варианти
enum Message {
Quit,
Move { x: i64, y: i64 },
Write(String),
ChangeColor(i64, i64, i64),
}
Enum варианти като структури
struct QuitMessage; // unit struct
struct MoveMessage {
x: i64,
y: i64,
}
struct WriteMessage(String); // tuple struct
struct ChangeColorMessage(i64, i64, i64); // tuple struct
Разполагане в паметта
Вариант | Памет | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
8B | 24B | ||||||||||||
Quit | 0 | ||||||||||||
Move { x: i64, y: i64 } | 1 | i64 | i64 | ||||||||||
Write(String) | 2 | String | |||||||||||
ChangeColor(i64, i64, i64) | 3 | i64 | i64 | i64 |
- 8 байта за дискриминанта
- 24 байта за данните
Методи
enum Message { ... }
impl Message {
fn call(&self) {
// ...
}
}
let m = Message::Write(String::from("hello"));
m.call();
Енумерации
- Скучно име, идващо от C, където са доста ограничени
Енумерации
- Скучно име, идващо от C, където са доста ограничени
- По-готиното име е "алгебричен тип", и е мощно средство за типови шмекерии
Енумерацията Option
Енумерацията Option
- Понякога искаме да изразим липсваща стойност.
Енумерацията Option
- Понякога искаме да изразим липсваща стойност.
- Проблема обикновено се решава със специалната стойност
NULL
.
Енумерацията Option
- Понякога искаме да изразим липсваща стойност.
- Проблема обикновено се решава със специалната стойност
NULL
. - Това води до готини неща като "тройни булеви стойности" и любимите на всички null pointer exceptions.
Енумерацията Option
- Понякога искаме да изразим липсваща стойност.
- Проблема обикновено се решава със специалната стойност
NULL
. - Това води до готини неща като "тройни булеви стойности" и любимите на всички null pointer exceptions.
- Тук-таме
NULL
се използва и за "имаше грешка, но¯\_(ツ)_/¯
каква"
Енумерацията Option
- Понякога искаме да изразим липсваща стойност.
- Проблема обикновено се решава със специалната стойност
NULL
. - Това води до готини неща като "тройни булеви стойности" и любимите на всички null pointer exceptions.
- Тук-таме
NULL
се използва и за "имаше грешка, но¯\_(ツ)_/¯
каква" - В Rust няма
NULL
!
Енумерацията Option
Option има 2 стойности:
Some(val)
None
Енумерацията Option
let some_number = Some(5);
let some_string = Some("string");
let absent_number: Option<i32> = None;
println!("{:?}", some_number);
println!("{:?}", some_string);
println!("{:?}", absent_number);
Some(5) Some("string") None
Pattern Matching
Съпоставяне на образци
Pattern Matching
Съпоставяне на образци
- Идея идваща от функционалното програмиране
Pattern Matching
Съпоставяне на образци
- Идея идваща от функционалното програмиране
- Може да се ползва с енумерации и стойности в тях
Pattern Matching
Съпоставяне на образци
- Идея идваща от функционалното програмиране
- Може да се ползва с енумерации и стойности в тях
- Използва се чрез
match
оператора
Pattern Matching
Съпоставяне на образци
let x = Some(42_u32);
match x {
Some(val) => println!("Value : {}", val),
None => println!("No value found"),
}
Value : 42
Pattern Matching
Съпоставяне на образци
let x: Option<u32> = None;
match x {
Some(val) => println!("Value : {}", val),
None => println!("No value found"),
}
No value found
Pattern Matching
Съпоставяне на образци
match
може да върне стойност:
let x = Some(4);
let y = match x {
Some(val) => Some(val * val),
None => None,
};
println!("{:?}", y);
Some(16)
Pattern Matching
Съпоставяне на образци
match
може да върне стойност:
let x = Some(4);
let y = match x {
Some(val) => val * val,
None => 0,
};
println!("{:?}", y);
16
Pattern Matching
Съпоставяне на образци
match
може да излезе от функцията
let y = match x {
Some(val) => val * val,
None => return None,
};
Pattern Matching
Съпоставяне на образци
match
може да съдържа блокове от код:
let y = match x {
Some(val) => {
println!("Will return {}", val * val);
Some(val * val)
},
None => {
println!("Will do nothing!!");
None
},
};
Pattern Matching
Съпоставяне на образци
Задължително трябва да се покрият всички случаи!
let x = Some(3);
let y = match x {
Some(i) => Some(i + 1),
};
error[E0004]: non-exhaustive patterns: `None` not covered --> /src/main_5.rs:4:15 | 4 | let y = match x { | ^ pattern `None` not covered
Pattern Matching
Съпоставяне на образци
Работи и с прости стойности: _
означава всичко останало
match x {
69 => println!("Nice."),
666 => println!("\m/"),
_ => println!("¯\_(ツ)_/¯"),
}
More control flow
if let
Понякога да използваме match
за един случай и да покрием всички други с _
е прекалено много код
let some_value = Some(8);
match some_value {
Some(8) => println!("8)"),
_ => (),
}
8)
More control flow
if let
Запознайте се с if let
:
let some_value = Some(8);
if let Some(8) = some_value {
println!("::::)");
}
::::)
More control flow
while let
А защо не и while let
:
let so_eighty = [8, 8, 8, 88, 8];
let mut iter8or = so_eighty.iter();
while let Some(8) = iter8or.next() {
println!("∞");
}
∞ ∞ ∞
Итерация
let numbers = [1, 2, 3].iter(); // std::slice::Iter
let chars = "abc".chars(); // std::str::Chars
let words = "one two three".split_whitespace(); // std::str::SplitWhitespace
Итерация
let numbers = [1, 2, 3].iter(); // std::slice::Iter
let chars = "abc".chars(); // std::str::Chars
let words = "one two three".split_whitespace(); // std::str::SplitWhitespace
println!("{:?}", numbers);
println!("{:?}", chars);
println!("{:?}", words);
Iter([1, 2, 3]) Chars { iter: Iter([97, 98, 99]) } SplitWhitespace { inner: Filter { iter: Split(SplitInternal { start: 0, end: 13, matcher: CharPredicateSearcher { haystack: "one two three", char_indices: CharIndices { front_offset: 0, iter: Chars { iter: Iter([111, 110, 101, 32, 116, 119, 111, 32, 116, 104, 114, 101, 101]) } } }, allow_trailing_empty: true, finished: false }) } }
Итерация
let numbers: Vec<&u32> = [1, 2, 3].iter().collect();
let chars: Vec<char> = "abc".chars().collect();
let words: Vec<&str> = "one two three".split_whitespace().collect();
println!("{:?}", numbers);
println!("{:?}", chars);
println!("{:?}", words);
[1, 2, 3] ['a', 'b', 'c'] ["one", "two", "three"]
Итерация
let chars = String::from("abc").chars();
println!("{:?}", chars); // ???
Итерация
let chars = String::from("abc").chars();
println!("{:?}", chars);
error[E0597]: borrowed value does not live long enough --> /src/main_11.rs:2:13 | 2 | let chars = String::from("abc").chars(); | ^^^^^^^^^^^^^^^^^^^ - temporary value dropped here while still borrowed | | | temporary value does not live long enough ... 5 | } | - temporary value needs to live until here | = note: consider using a `let` binding to increase its lifetime
Итерация
let string = String::from("abc");
let chars = string.chars();
println!("{:?}", chars);
Chars { iter: Iter([97, 98, 99]) }
Итерация
let string = String::from("abc");
let mut chars = string.chars(); // Mutable!
println!("{:?}", chars.next());
println!("{:?}", chars.next());
println!("{:?}", chars.next());
println!("{:?}", chars.next());
Some('a') Some('b') Some('c') None
Итерация
let string = String::from("abc");
let mut chars = string.chars(); // Mutable!
while let Some(c) = chars.next() {
println!("{:?}", c);
}
'a' 'b' 'c'
Итерация
let string = String::from("abc");
let mut chars = string.chars();
for c in chars {
println!("{:?}", c);
}
Итерация
let string = String::from("abc");
let mut chars = string.chars();
for c in chars {
println!("{:?}", c);
}
warning: variable does not need to be mutable --> /src/main_15.rs:3:5 | 3 | let mut chars = string.chars(); | ----^^^^^ | | | help: remove this `mut` | = note: #[warn(unused_mut)] on by default
Итерация
let string = String::from("abc");
let chars = string.chars(); // Not Mutable!
for c in chars {
println!("{:?}", c);
}
'a' 'b' 'c'
More control flow
All together now:
let counts = [1, 2, 3, 4];
let mut counter = counts.iter();
if let Some(n) = counter.next() {
print!("{}", n);
while let Some(n) = counter.next() {
print!(" and {}", n);
}
println!();
}
More control flow
All together now:
let counts = [1, 2, 3, 4];
let mut counter = counts.iter();
if let Some(n) = counter.next() {
print!("{}", n);
while let Some(n) = counter.next() {
print!(" and {}", n);
}
println!();
}
1 and 2 and 3 and 4
Pattern Matching
Guards (допълнителни условия)
let pair = (2, -2);
match pair {
(x, y) if x == y => println!("Едно и също"),
(x, y) if x + y == 0 => println!("Противоположни"),
(x, y) if x % 2 == 1 && y % 2 == 0 => println!("X е нечетно, Y е четно"),
(x, _) if x % 2 == 1 => println!("X е нечетно"),
_ => println!("Нищо интересно"),
}
Pattern Matching
Ranges
let age: i32 = -5;
match age {
n if n < 0 => println!("Ще се родя след {} години.", n.abs()),
0 => println!("Новородено съм."),
1 ... 12 => println!("Аз съм лапе."),
13 ... 19 => println!("Аз съм тийн."),
_ => println!("Аз съм дърт."),
}
Pattern Matching
Bindings
let age: i32 = -5;
match age {
n if n < 0 => println!("Ще се родя след {} години.", n.abs()),
0 => println!("Новородено съм."),
n @ 1 ... 12 => println!("Аз съм лапе на {}.", n),
n @ 13 ... 19 => println!("Аз съм тийн на {}.", n),
n => println!("Аз съм дърт, на {} съм вече.", n),
}
Pattern Matching
Multiple patterns
let score: u32 = 5;
match score {
0 | 1 => println!("слабичко :("),
_ => println!("стаа"),
}
Pattern Matching
Structs
struct User {
name: &'static str,
age: u8
}
let user = User {
name: "Пешо",
age: 12
};
match user {
User { name: "Пешо", age: _ } => println!("Ко стаа, Пешо"),
User { name: _, age: 12 } => println!("Ко стаа, лапе"),
User { name: x, .. } => println!("Ко стаа, {}", x),
_ => println!("Ко стаа")
}
Destructuring
ref
#[derive(Debug)]
enum Token { Text(String), Number(f64) }
fn main() {
let token = Token::Text(String::from("Отговора е 42"));
match token {
Token::Text(text) => println!("Токена е текст: '{}'", text),
Token::Number(n) => println!("Токена е число: {}", n),
}
println!("В крайна сметка, токена е {:?}!", token);
}
error[E0382]: use of partially moved value: `token` --> /src/main_18.rs:11:49 | 7 | Token::Text(text) => println!("Токена е текст: '{}'", text), | ---- value moved here ... 11 | println!("В крайна сметка, токена е {:?}!", token); | ^^^^^ value used here after move | = note: move occurs because the value has type `std::string::String`, which does not implement the `Copy` trait
Destructuring
ref
Чрез ref
стойността няма да се премести.
#[derive(Debug)]
enum Token { Text(String), Number(f64) }
fn main() {
let token = Token::Text(String::from("Отговора е 42"));
match token {
Token::Text(ref text) => println!("Токена е текст: '{}'", text),
Token::Number(n) => println!("Токена е число: {}", n),
}
println!("В крайна сметка, токена е {:?}!", token);
}
Токена е текст: 'Отговора е 42' В крайна сметка, токена е Text("Отговора е 42")!
Destructuring
ref
Какво всъщност прави ref
? Едно просто обяснение е чрез пример:
let x = &1;
let ref y = 1;
Destructuring
ref
Какво всъщност прави ref
? Едно просто обяснение е чрез пример:
let x = &1;
let ref y = 1;
- Двете променливи имат един и същ тип
Destructuring
ref
Какво всъщност прави ref
? Едно просто обяснение е чрез пример:
let x = &1;
let ref y = 1;
- Двете променливи имат един и същ тип
- Първият пример взима референция с
&
в дясната страна на твърдението
Destructuring
ref
Какво всъщност прави ref
? Едно просто обяснение е чрез пример:
let x = &1;
let ref y = 1;
- Двете променливи имат един и същ тип
- Първият пример взима референция с
&
в дясната страна на твърдението - Вторият пример взима референция с
ref
в лявата страна на твърдението
Destructuring
ref
Какво всъщност прави ref
? Едно просто обяснение е чрез пример:
let x = &1;
let ref y = 1;
- Двете променливи имат един и същ тип
- Първият пример взима референция с
&
в дясната страна на твърдението - Вторият пример взима референция с
ref
в лявата страна на твърдението - Това е важно, защото в
match
ръкава нямаме достъп до "дясната страна"
Destructuring
ref mut
Същата идея:
let mut token = Token::Text(String::from("Отговора е 42"));
match token {
Token::Text(ref mut text) => {
*text = String::from("Може би");
println!("Токена е Text('{}')", text)
},
Token::Number(n) => println!("Токена е Number({})", n),
}
Destructuring
let
let (mut a, b) = (1, 2);
let User { name: name, ..} = user;
let User { name, ..} = user;
let Some(val) = Some(5); // ??
Destructuring
let
let (mut a, b) = (1, 2);
// let User { name: name, ..} = user;
// let User { name, ..} = user;
let Some(val) = Some(5); // ??
error[E0005]: refutable pattern in local binding: `None` not covered --> /src/main_24.rs:5:5 | 5 | let Some(val) = Some(5); // ?? | ^^^^^^^^^ pattern `None` not covered
Refutable/Irrefutable patterns
let (a, b) = (1, 2); // -> Irrefutable pattern
if let Some(val) = Some(5) { // -> Refutable pattern
println!("Okay!");
}
Okay!
Refutable/Irrefutable patterns
if let (a, b) = (1, 2) {
println!("Nope!");
}
let Some(val) = Some(5);
error[E0162]: irrefutable if-let pattern --> /src/main_22.rs:3:8 | 3 | if let (a, b) = (1, 2) { | ^^^^^^ irrefutable pattern error[E0005]: refutable pattern in local binding: `None` not covered --> /src/main_22.rs:7:5 | 7 | let Some(val) = Some(5); | ^^^^^^^^^ pattern `None` not covered