Enums & Pattern-matching

("Изброени типове" и "съпоставяне на образци")

18 октомври 2022

Преговор

Преговор

Преговор

Преговор

Преговор

Enums

Enums

Enums

Enums

1 2 3 4
enum IpAddrKind {
    V4,
    V6,
}

Enums

Инстанциране

1 2
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;

Enums

Параметър

1 2 3 4
fn route(ip_type: IpAddrKind) { }

route(IpAddrKind::V4);
route(IpAddrKind::V6);

Enums

Данни

1 2 3 4 5 6 7 8 9 10 11 12 13 14
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

Данни

По-удобен и четим начин

1 2 3 4 5 6 7 8
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

1 2 3 4 5 6 7 8
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

Защо?

Enums

Защо?

Enums

Защо?

Enums

Защо?

1 2 3 4 5 6 7 8
struct IpAddr {
    v4: (u8, u8, u8, u8),
    v6: String,
}

// Warning: фалшив Rust код, няма NULL
let home = IpAddr { v4: (127, 0, 0, 1), v6: NULL };
let loopback = IpAddr { v4: NULL, v6: String::from("::1") };

Не е особено ясно -- човек трябва "да се усети" като чете кода.

Enums

Варианти

1 2 3 4 5 6 7 8 9 10 11
enum Message {
    Quit,
    Move { x: i64, y: i64 },
    Write(String),
    ChangeColor(i64, i64, i64),
}

Message::Quit;
Message::Move { x: 3, y: 4 };
Message::Write(String::from("baba"));
Message::ChangeColor(255, 0, 0);

Enum варианти като структури

1 2 3 4 5 6 7 8 9 10 11 12
struct QuitMessage; // unit struct
struct MoveMessage {
    x: i64,
    y: i64,
}
struct WriteMessage(String); // tuple struct
struct ChangeColorMessage(i64, i64, i64); // tuple struct

QuitMessage;
MoveMessage { x: 3, y: 4 };
WriteMessage(String::from("baba"));
ChangeColorMessage(255, 0, 0);

Методи

1 2 3 4 5 6 7 8 9 10
enum Message { ... }

impl Message {
    fn call(&self) {
        // ...
    }
}

let m = Message::Write(String::from("hello"));
m.call();

Методи

1 2 3 4 5 6 7 8 9 10
enum Message { ... }

impl Message {
    fn call(&self) {
        // ...
    }
}

let m = Message::Write(String::from("hello"));
m.call();

А какво точно правим вътре в call? Ще видим след няколко слайда :)

Разполагане в паметта

Вариант Памет
8B 24B
Quit 0
Move { x: i64, y: i64 } 1 i64 i64
Write(String) 2 String
ChangeColor(i64, i64, i64) 3 i64 i64 i64

Без дискриминанта

1 2 3 4 5 6 7 8 9 10
use std::mem;

enum Basic {
    A,
    B,
}

fn main() {
    println!("{:?}", mem::size_of::<Basic>());
}
1
use std::mem;

enum Basic {
    A,
    B,
}

fn main() {
    println!("{:?}", mem::size_of::());
}

Null-pointer optimization

1 2 3 4 5 6 7 8 9 10 11
use std::mem;

enum LeanAndMean {
    A,
    B(String),
}

fn main() {
    println!("Without enum: {:?}", mem::size_of::<String>());
    println!("With enum:    {:?}", mem::size_of::<LeanAndMean>());
}
Without enum: 24 With enum: 24
use std::mem;

enum LeanAndMean {
    A,
    B(String),
}

fn main() {
    println!("Without enum: {:?}", mem::size_of::());
    println!("With enum:    {:?}", mem::size_of::());
}

Null-pointer optimization

1 2 3 4 5 6 7 8 9 10 11 12
use std::mem;

enum JustMean {
    A,
    B(String),
    C,
}

fn main() {
    println!("Without enum: {:?}", mem::size_of::<String>());
    println!("With enum:    {:?}", mem::size_of::<JustMean>());
}
Without enum: 24 With enum: 32
use std::mem;

enum JustMean {
    A,
    B(String),
    C,
}

fn main() {
    println!("Without enum: {:?}", mem::size_of::());
    println!("With enum:    {:?}", mem::size_of::());
}

Енума Option

Енума Option

Енума Option

Енума Option

Енума Option

Енума Option

Енума Option

Option има 2 стойности:

Енума Option

1 2 3 4 5 6 7
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
fn main() {
let some_number = Some(5);
let some_string = Some("string");
let absent_number: Option = None;

println!("{:?}", some_number);
println!("{:?}", some_string);
println!("{:?}", absent_number);
}

Енума Option

1 2 3 4 5 6 7
let some_number: Option<u32> = Some(5);
let some_string: Option<&str> = Some("string");
let absent_number: Option<i32> = None;

println!("{:?}", some_number);
println!("{:?}", some_string);
println!("{:?}", absent_number);
Some(5) Some("string") None
fn main() {
let some_number: Option = Some(5);
let some_string: Option<&str> = Some("string");
let absent_number: Option = None;

println!("{:?}", some_number);
println!("{:?}", some_string);
println!("{:?}", absent_number);
}

Pattern Matching

"Съпоставяне на образци"

Pattern Matching

"Съпоставяне на образци"

Pattern Matching

"Съпоставяне на образци"

Pattern Matching

"Съпоставяне на образци"

Pattern Matching

1 2 3 4 5 6
let x = Some(42_u32);

match x {
    Some(val) => println!("Value: {}", val),
    None      => println!("No value found"),
}
Value: 42
fn main() {
let x = Some(42_u32);

match x {
    Some(val) => println!("Value: {}", val),
    None      => println!("No value found"),
}
}

Pattern Matching

1 2 3 4 5 6
let x: Option<u32> = None;

match x {
    Some(val) => println!("Value: {}", val),
    None      => println!("No value found"),
}
No value found
fn main() {
let x: Option = None;

match x {
    Some(val) => println!("Value: {}", val),
    None      => println!("No value found"),
}
}

Pattern Matching

match може да върне стойност:

1 2 3 4 5 6 7 8
let x = Some(4);

let y = match x {
    Some(val) => Some(val * val),
    None => None,
};

println!("{:?}", y);
Some(16)
fn main() {
let x = Some(4);

let y = match x {
    Some(val) => Some(val * val),
    None => None,
};

println!("{:?}", y);
}

Pattern Matching

match може да върне стойност:

1 2 3 4 5 6 7 8
let x = Some(4);

let y = match x {
    Some(val) => val * val,
    None => 0,
};

println!("{:?}", y);
16
fn main() {
let x = Some(4);

let y = match x {
    Some(val) => val * val,
    None => 0,
};

println!("{:?}", y);
}

Pattern Matching

match може да излезе от функцията

1 2 3 4
let y = match x {
    Some(val) => val * val,
    None => return None,
};

Pattern Matching

match може да съдържа блокове от код:

1 2 3 4 5 6 7 8 9 10
let y = match x {
    Some(val) => {
        println!("Will return {}", val * val);
        Some(val * val)
    },
    None => {
        println!("Will do nothing!!");
        None
    },
};

Pattern Matching

Задължително трябва да се покрият всички случаи!

1 2 3 4 5
let x = Some(3);

let y = match x {
    Some(i) => Some(i + 1),
};
error[E0004]: non-exhaustive patterns: `None` not covered --> src/bin/main_95c8682b7401bcccd982dc5ffc0ed7d72379cdae.rs:4:15 | 4 | let y = match x { | ^ pattern `None` not covered | note: `Option<i32>` defined here --> /home/andrew/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:522:5 | 518 | pub enum Option<T> { | ------------------ ... 522 | None, | ^^^^ not covered = note: the matched value is of type `Option<i32>` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | 5 ~ Some(i) => Some(i + 1), 6 ~ None => todo!(), | For more information about this error, try `rustc --explain E0004`. error: could not compile `rust` due to previous error
fn main() {
let x = Some(3);

let y = match x {
    Some(i) => Some(i + 1),
};
}

Pattern Matching

Работи и с прости стойности: _ означава всичко останало

1 2 3 4 5
match x {
    69  => println!("Nice."),
    666 => println!(r"\m/"),
    _   => println!(r"¯\_(ツ)_/¯"),
}

Pattern Matching

НО! Ръкавите трябва да са от един и същ тип

1 2 3 4 5
let response = match x {
    69  => "Nice!",
    666 => r"\m/",
    _   => 0_0,
};
error[E0308]: `match` arms have incompatible types --> src/bin/main_48ccf2f6abbea81f52e3d53a72c573d98dd05a43.rs:6:12 | 3 | let response = match x { | ________________- 4 | | 69 => "Nice!", | | ------- this is found to be of type `&str` 5 | | 666 => r"\m/", | | ------ this is found to be of type `&str` 6 | | _ => 0_0, | | ^^^ expected `&str`, found integer 7 | | }; | |_- `match` arms have incompatible types For more information about this error, try `rustc --explain E0308`. error: could not compile `rust` due to previous error
fn main() {
let x = 3;
let response = match x {
    69  => "Nice!",
    666 => r"\m/",
    _   => 0_0,
};
}

More control flow

if let

Понякога да използваме match за един случай и да покрием всички други с _ е прекалено много код

1 2 3 4 5 6
let some_value = Some(8);

match some_value {
    Some(8) => println!("8)"),
    _ => (),
}
8)
fn main() {
let some_value = Some(8);

match some_value {
    Some(8) => println!("8)"),
    _ => (),
}
}

More control flow

if let

Запознайте се с if let:

1 2 3 4 5
let some_value = Some(8);

if let Some(8) = some_value {
    println!("::::)");
}
::::)
fn main() {
let some_value = Some(8);

if let Some(8) = some_value {
    println!("::::)");
}
}

More control flow

while let

А защо не и while let:

1 2 3 4 5 6
let so_eighty = [8, 8, 8, 88, 8];
let mut iter8or = so_eighty.iter();

while let Some(8) = iter8or.next() {
    println!("∞");
}
∞ ∞ ∞
fn main() {
let so_eighty = [8, 8, 8, 88, 8];
let mut iter8or = so_eighty.iter();

while let Some(8) = iter8or.next() {
    println!("∞");
}
}

Итерация

… и някои леко неинтуитивни изненади

1 2 3
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

Итерация

1 2 3 4 5 6 7
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(['a', 'b', 'c']) SplitWhitespace { inner: Filter { iter: Split(SplitInternal { start: 0, end: 13, matcher: CharPredicateSearcher { haystack: "one two three", char_indices: CharIndices { front_offset: 0, iter: Chars(['o', 'n', 'e', ' ', 't', 'w', 'o', ' ', 't', 'h', 'r', 'e', 'e']) } }, allow_trailing_empty: true, finished: false }) } }
fn main() {
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);
}

Итерация

1 2 3 4 5 6 7
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"]
fn main() {
let numbers: Vec<&u32> = [1, 2, 3].iter().collect();
let chars: Vec  = "abc".chars().collect();
let words: Vec<&str>  = "one two three".split_whitespace().collect();

println!("{:?}", numbers);
println!("{:?}", chars);
println!("{:?}", words);
}

Итерация

1 2 3
let chars = String::from("abc").chars();

println!("{:?}", chars); // ???

Итерация

1 2 3
let chars = String::from("abc").chars();

println!("{:?}", chars);
error[E0716]: temporary value dropped while borrowed --> src/bin/main_fdc3411ae2754f8f369a49979e61218b7638899c.rs:2:13 | 2 | let chars = String::from("abc").chars(); | ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | | creates a temporary which is freed while still in use 3 | 4 | println!("{:?}", chars); | ----- borrow later used here | help: consider using a `let` binding to create a longer lived value | 2 + let binding = String::from("abc"); 3 ~ let chars = binding.chars(); | For more information about this error, try `rustc --explain E0716`. error: could not compile `rust` due to previous error
fn main() {
let chars = String::from("abc").chars();

println!("{:?}", chars);
}

Итерация

1 2 3 4
let string = String::from("abc");
let chars = string.chars();

println!("{:?}", chars);
Chars(['a', 'b', 'c'])
fn main() {
let string = String::from("abc");
let chars = string.chars();

println!("{:?}", chars);
}

Итерация

1 2 3 4 5 6 7
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
fn main() {
let string = String::from("abc");
let mut chars = string.chars(); // Mutable!

println!("{:?}", chars.next());
println!("{:?}", chars.next());
println!("{:?}", chars.next());
println!("{:?}", chars.next());
}

Итерация

1 2 3 4 5 6
let string = String::from("abc");
let mut chars = string.chars(); // Mutable!

while let Some(c) = chars.next() {
    println!("{:?}", c);
}
'a' 'b' 'c'
fn main() {
let string = String::from("abc");
let mut chars = string.chars(); // Mutable!

while let Some(c) = chars.next() {
    println!("{:?}", c);
}
}

Итерация

1 2 3 4 5 6
let string = String::from("abc");
let mut chars = string.chars();

for c in chars {
    println!("{:?}", c);
}

Итерация

1 2 3 4 5 6
let string = String::from("abc");
let mut chars = string.chars();

for c in chars {
    println!("{:?}", c);
}
'a' 'b' 'c'
fn main() {
let string = String::from("abc");
let mut chars = string.chars();

for c in chars {
    println!("{:?}", c);
}
}

Итерация

1 2 3 4 5 6
let string = String::from("abc");
let chars = string.chars(); // Not Mutable!

for c in chars {
    println!("{:?}", c);
}
'a' 'b' 'c'
fn main() {
let string = String::from("abc");
let chars = string.chars(); // Not Mutable!

for c in chars {
    println!("{:?}", c);
}
}

Итерация

1 2 3 4 5 6 7 8 9 10
let string = String::from("abc");
let chars = string.chars(); // Not Mutable!

{
    // (sneakily add mutability)
    let mut chars = chars;
    for c in chars {
        println!("{:?}", c);
    }
}
'a' 'b' 'c'
fn main() {
let string = String::from("abc");
let chars = string.chars(); // Not Mutable!

{
    // (sneakily add mutability)
    let mut chars = chars;
    for c in chars {
        println!("{:?}", c);
    }
}
}

More control flow

All together now:

1 2 3 4 5 6 7 8 9 10
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:

1 2 3 4 5 6 7 8 9 10
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
fn main() {
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!();
}
}

Pattern Matching

Guards (допълнителни условия)

1 2 3 4 5 6 7 8 9
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

1 2 3 4 5 6 7 8 9
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

1 2 3 4 5 6 7 8 9
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

1 2 3 4 5 6
let score: u32 = 5;

match score {
    0 | 1 => println!("слабичко :("),
    _     => println!("стаа"),
}

Pattern Matching

Structs

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
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!("Ко стаа")
}

Pattern Matching

Slice

1 2 3 4 5 6 7
let cake: &[&str] = &["vanilla", "strawberry", "chocolate"];

match cake {
    []         => println!("Turns out it's a lie :/"),
    [one_item] => println!("One slice is better than nothing"),
    _          => println!("Wow, that's a lotta slices!")
}
Wow, that's a lotta slices!
fn main() {
let cake: &[&str] = &["vanilla", "strawberry", "chocolate"];

match cake {
    []         => println!("Turns out it's a lie :/"),
    [one_item] => println!("One slice is better than nothing"),
    _          => println!("Wow, that's a lotta slices!")
}
}

Нищо по-fancy засега… очакват се по-интересни неща по-нататък.

Pattern Matching

Slice

Защо ни трябва експлицитен &[&str]

1 2 3 4 5 6 7 8
let cake = &["vanilla", "strawberry", "chocolate"];
// => &[&str; 3]

match cake {
    []         => println!("Turns out it's a lie :/"),
    [one_item] => println!("One slice is better than nothing"),
    _          => println!("Wow, that's a lotta slices!")
}
error[E0527]: pattern requires 0 elements but array has 3 --> src/bin/main_7fcc5d4a5bf3f85fa23c4492b0dcf73948710ca7.rs:6:5 | 6 | [] => println!("Turns out it's a lie :/"), | ^^ expected 3 elements error[E0527]: pattern requires 1 element but array has 3 --> src/bin/main_7fcc5d4a5bf3f85fa23c4492b0dcf73948710ca7.rs:7:5 | 7 | [one_item] => println!("One slice is better than nothing"), | ^^^^^^^^^^ expected 3 elements For more information about this error, try `rustc --explain E0527`. error: could not compile `rust` due to 2 previous errors
fn main() {
let cake = &["vanilla", "strawberry", "chocolate"];
// => &[&str; 3]

match cake {
    []         => println!("Turns out it's a lie :/"),
    [one_item] => println!("One slice is better than nothing"),
    _          => println!("Wow, that's a lotta slices!")
}
}

Pattern Matching

Unambiguous

1 2 3 4 5 6 7
let numbers = (2, 4, 8, 16, 32);

match numbers {
    (.., second, ..) => {
        println!("Some numbers: {}", second)
    },
}
error: `..` can only be used once per tuple pattern --> src/bin/main_0785486a8cc5ddcdb61694d420d4508a1c40d033.rs:5:18 | 5 | (.., second, ..) => { | -- ^^ can only be used once per tuple pattern | | | previously used here error: could not compile `rust` due to previous error
fn main() {
let numbers = (2, 4, 8, 16, 32);

match numbers {
    (.., second, ..) => {
        println!("Some numbers: {}", second)
    },
}
}

Destructuring

1 2 3 4 5 6 7 8 9 10
#[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),
    }
}
Токена е текст: 'Отговора е 42'
#[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),
    }
}

Destructuring

1 2 3 4 5 6 7 8 9 10 11 12
#[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]: borrow of partially moved value: `token` --> src/bin/main_7de83c4ece9c335fd8a37b17110e37b3955439df.rs:11:49 | 7 | Token::Text(text) => println!("Токена е текст: '{}'", text), | ---- value partially moved here ... 11 | println!("В крайна сметка, токена е {:?}!", token); | ^^^^^ value borrowed here after partial move | = note: partial move occurs because value has type `String`, which does not implement the `Copy` trait = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) help: borrow this field in the pattern to avoid moving `token.0` | 7 | Token::Text(ref text) => println!("Токена е текст: '{}'", text), | +++ For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` due to previous error
#[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);
}

Destructuring

match token -> match &token

1 2 3 4 5 6 7 8 9 10 11 12
#[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);
}
Токена е текст: 'Отговора е 42' В крайна сметка, токена е Text("Отговора е 42")!
#[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);
}

Destructuring

Друг вариант: ref

Чрез ref стойността няма да се премести.

1 2 3 4 5 6 7 8 9 10 11 12
#[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")!
#[allow(dead_code)]
#[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);
}

Destructuring

ref

Какво всъщност прави ref? Едно просто обяснение е чрез пример:

1 2 3
let x = &1_u32;

let ref y = 1_u32;

Destructuring

ref

Какво всъщност прави ref? Едно просто обяснение е чрез пример:

1 2 3
let x = &1_u32;

let ref y = 1_u32;

Destructuring

ref

Какво всъщност прави ref? Едно просто обяснение е чрез пример:

1 2 3
let x = &1_u32;

let ref y = 1_u32;

Destructuring

ref

Какво всъщност прави ref? Едно просто обяснение е чрез пример:

1 2 3
let x = &1_u32;

let ref y = 1_u32;

Destructuring

ref

Какво всъщност прави ref? Едно просто обяснение е чрез пример:

1 2 3
let x = &1_u32;

let ref y = 1_u32;

Destructuring

Destructuring

Destructuring

Destructuring

Destructuring

&mut

Същата идея:

1 2 3 4 5 6 7 8 9
let mut token = Token::Text(String::from("Отговора е 42"));

match &mut token {
    Token::Text(text) => {
        *text = String::from("Може би");
        println!("Токена е Text('{}')", text)
    },
    Token::Number(n) => println!("Токена е Number({})", n),
}
Токена е Text('Може би')
#[allow(dead_code)]
#[derive(Debug)]
enum Token { Text(String), Number(f64) }
fn main() {
let mut token = Token::Text(String::from("Отговора е 42"));

match &mut token {
    Token::Text(text) => {
        *text = String::from("Може би");
        println!("Токена е Text('{}')", text)
    },
    Token::Number(n) => println!("Токена е Number({})", n),
}
}

Destructuring

ref mut

Същата идея:

1 2 3 4 5 6 7 8 9
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),
}
Токена е Text('Може би')
#[allow(dead_code)]
#[derive(Debug)]
enum Token { Text(String), Number(f64) }
fn main() {
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

1 2 3 4
let (mut a, b) = (1, 2);
let User { name: name_var, .. } = user;
let User { name, .. } = user;
let Some(val) = Some(5);    // ??

Destructuring

let

1 2 3 4
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/bin/main_d1511059f296e51051e460e98c50c64b6a469db5.rs:5:5 | 5 | let Some(val) = Some(5); // ?? | ^^^^^^^^^ pattern `None` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `Option<i32>` defined here --> /home/andrew/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:522:5 | 518 | pub enum Option<T> { | ------------------ ... 522 | None, | ^^^^ not covered = note: the matched value is of type `Option<i32>` help: you might want to use `if let` to ignore the variant that isn't matched | 5 | let val = if let Some(val) = Some(5) { val } else { todo!() }; // ?? | ++++++++++++ ++++++++++++++++++++++++ For more information about this error, try `rustc --explain E0005`. error: could not compile `rust` due to previous error
fn main() {
let (mut a, b) = (1, 2);
// let User { name: name, .. } = user;
// let User { name, .. } = user;
let Some(val) = Some(5);    // ??
}

Refutable/Irrefutable patterns

1 2 3 4 5
let (a, b) = (1, 2); // -> Irrefutable pattern

if let Some(val) = Some(5) { // -> Refutable pattern
    println!("Okay!");
}
Okay!
#[allow(unused_variables)]
fn main() {
let (a, b) = (1, 2); // -> Irrefutable pattern

if let Some(val) = Some(5) { // -> Refutable pattern
    println!("Okay!");
}
}

Refutable/Irrefutable patterns

1 2 3 4 5
if let (a, b) = (1, 2) {
    println!("Nope!");
}

let Some(val) = Some(5);
warning: irrefutable `if let` pattern --> src/bin/main_a7d8ae0df38a9baad785d12585ab8eec8e5c4c94.rs:3:4 | 3 | if let (a, b) = (1, 2) { | ^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(irrefutable_let_patterns)]` on by default = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` error[E0005]: refutable pattern in local binding: `None` not covered --> src/bin/main_a7d8ae0df38a9baad785d12585ab8eec8e5c4c94.rs:7:5 | 7 | let Some(val) = Some(5); | ^^^^^^^^^ pattern `None` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html note: `Option<i32>` defined here --> /home/andrew/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:522:5 | 518 | pub enum Option<T> { | ------------------ ... 522 | None, | ^^^^ not covered = note: the matched value is of type `Option<i32>` help: you might want to use `if let` to ignore the variant that isn't matched | 7 | let val = if let Some(val) = Some(5) { val } else { todo!() }; | ++++++++++++ ++++++++++++++++++++++++ For more information about this error, try `rustc --explain E0005`. error: could not compile `rust` due to previous error; 1 warning emitted
#[allow(unused_variables)]
fn main() {
if let (a, b) = (1, 2) {
    println!("Nope!");
}

let Some(val) = Some(5);
}

Refutable/Irrefutable patterns

1 2 3 4 5 6 7 8 9
if let (1, b) = (1, 2) {
    println!("{}", b);
}

if let (8, b) = (1, 2) {
    println!("{}", b);
} else {
    println!("8(");
}
2 8(
#[allow(unused_variables)]
fn main() {
if let (1, b) = (1, 2) {
    println!("{}", b);
}

if let (8, b) = (1, 2) {
    println!("{}", b);
} else {
    println!("8(");
}
}

Refutable/Irrefutable patterns

???

1 2 3 4 5 6 7
if let x = true {
    println!("Yup! x = {:?}", x)
}

if let x = false {
    println!("Also yup! x = {:?}", x)
}

Refutable/Irrefutable patterns

big if true

1 2 3 4 5 6 7
if let x = true {
    println!("Yup! x = {:?}", x)
}

if let x = false {
    println!("Also yup! x = {:?}", x)
}
Yup! x = true Also yup! x = false
#[allow(unused_variables)]
#[allow(irrefutable_let_patterns)]

fn main() {
if let x = true {
    println!("Yup! x = {:?}", x)
}

if let x = false {
    println!("Also yup! x = {:?}", x)
}
}

Refutable/Irrefutable patterns

big if true

1 2 3 4 5 6 7
if let x = true {
    println!("Yup! x = {:?}", x)
}

if let x = false {
    println!("Also yup! x = {:?}", x)
}
warning: irrefutable `if let` pattern --> src/bin/main_3464eb22dfe37dec3f5434c2be941b286610f0e2.rs:4:4 | 4 | if let x = true { | ^^^^^^^^^^^^ | = note: `#[warn(irrefutable_let_patterns)]` on by default = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let` warning: irrefutable `if let` pattern --> src/bin/main_3464eb22dfe37dec3f5434c2be941b286610f0e2.rs:8:4 | 8 | if let x = false { | ^^^^^^^^^^^^^ | = note: this pattern will always match, so the `if let` is useless = help: consider replacing the `if let` with a `let`
#[allow(unused_variables)]

fn main() {
if let x = true {
    println!("Yup! x = {:?}", x)
}

if let x = false {
    println!("Also yup! x = {:?}", x)
}
}

Някои линкове

Въпроси