Еnums, pattern matching, iteration

Енумерации, съпоставяне на образци, итерация

21 октомври 2025

Преговор

1 2 3 4 5 6
let s1 = String::from("foo bar");

let s2 = s1;

// println!("{}", s1); // error: use of moved value
println!("{}", s2);
foo bar
fn main() {
let s1 = String::from("foo bar");

let s2 = s1;

// println!("{}", s1); // error: use of moved value
println!("{}", s2);
}

Преговор

Преговор

Преговор

Преговор

Резени, масиви и низове

Масив Низ
статичен [T; N] - собственост над стойността
динамичен Vec<T> String собственост над стойността
резен &[T] &str заета назаем стойност (borrow)
mutable резен &mut [T] &mut str заета назаем стойност (borrow)

Структури

Структури

Синтаксис

1 2 3 4 5
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
}
struct User {
    username: String,
    email: String,
    sign_in_count: u64,
}
fn main() {}

Методи и асоциирани функции

Асоциирани функции

1 2 3 4 5 6 7 8 9 10 11
struct User { /* ... */ }

impl User {
    fn new(username: String, email: String) -> User {
        User {
            username: username,
            email: email,
            sign_in_count: 0,
        }
    }
}
fn main() {}
struct User { username: String, email: String, sign_in_count: u64 }
/*
struct User { /* ... */ }
*/

impl User {
    fn new(username: String, email: String) -> User {
        User {
            username: username,
            email: email,
            sign_in_count: 0,
        }
    }
}

Методи и асоциирани функции

Асоциирани функции

1 2 3 4 5 6 7 8 9 10 11 12 13
struct User { /* ... */ }

impl User {
    fn new(username: String, email: String) -> User {
        User {
            username: username,
            email: email,
            sign_in_count: 0,
        }
    }
}

let user = User::new(String::from("Иванчо"), String::from("ivan40@example.com"));
struct User { username: String, email: String, sign_in_count: u64 }
/*
struct User { /* ... */ }
*/

impl User {
    fn new(username: String, email: String) -> User {
        User {
            username: username,
            email: email,
            sign_in_count: 0,
        }
    }
}

fn main() {
let user = User::new(String::from("Иванчо"), String::from("ivan40@example.com"));
}

Методи и асоциирани функции

Конструктори и деструктори

Методи и асоциирани функции

Конструктори и деструктори

Методи и асоциирани функции

Конструктори и деструктори

Методи и асоциирани функции

Конструктори и деструктори

Методи и асоциирани функции

Конструктори и деструктори

Методи и асоциирани функции

Конструктори и деструктори

Методи и асоциирани функции

Конструктори и деструктори

Методи и асоциирани функции

Конструктори и деструктори

Методи и асоциирани функции

Конструктори и деструктори

Методи и асоциирани функции

Методи

1 2 3 4 5 6 7 8 9 10 11 12
struct User { /* ... */ }

impl User {
    fn check_and_sign_in(&mut self, email: &str) -> bool {
        if self.email == email {
            self.sign_in_count += 1;
            true
        } else {
            false
        }
    }
}
struct User { username: String, email: String, sign_in_count: u32 }
/*
struct User { /* ... */ }
*/

impl User {
    fn check_and_sign_in(&mut self, email: &str) -> bool {
        if self.email == email {
            self.sign_in_count += 1;
            true
        } else {
            false
        }
    }
}
fn main() {}

Методи и асоциирани функции

Методи

Методи и асоциирани функции

Типа Self

1 2 3 4 5 6 7 8 9 10 11 12
struct Rectangle { width: f64, height: f64 }

impl Rectangle {
    fn new(width: f64, height: f64) -> Self {
        Self { width, height }
    }

    // еквивалентно на
    fn new(width: f64, height: f64) -> Rectangle {
        Rectangle { width, height }
    }
}

Методи и асоциирани функции

Методи

1 2 3 4 5 6 7 8 9 10 11 12
struct Rectangle { width: f64, height: f64 }

impl Rectangle {
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();

println!("area = {}", area);
area = 6
struct Rectangle { width: f64, height: f64 }

impl Rectangle {
fn new(width: f64, height: f64) -> Self { Self { width, height } }
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

fn main() {
let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();

println!("area = {}", area);
}

Методи и асоциирани функции

Методи

1 2 3 4 5 6 7 8 9 10 11 12
struct Rectangle { width: f64, height: f64 }

impl Rectangle {
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

let rect = Rectangle::new(2.0, 3.0);
let area = Rectangle::area(&rect);

println!("area = {}", area);
area = 6
struct Rectangle { width: f64, height: f64 }

impl Rectangle {
fn new(width: f64, height: f64) -> Self { Self { width, height } }
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

fn main() {
let rect = Rectangle::new(2.0, 3.0);
let area = Rectangle::area(&rect);

println!("area = {}", area);
}

Методи и асоциирани функции

Множество impl блокове

Позволено е декларирането на повече от един impl блок за структура.

1 2 3 4 5 6 7 8 9 10 11 12 13
struct Rectangle { width: f64, height: f64 }

impl Rectangle {
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

impl Rectangle {
    fn perimeter(&self) -> f64 {
        2.0 * (self.width + self.height)
    }
}
struct Rectangle { width: f64, height: f64 }

impl Rectangle {
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

impl Rectangle {
    fn perimeter(&self) -> f64 {
        2.0 * (self.width + self.height)
    }
}
fn main() {}

Структури

Ниво на достъп

По подразбиране, всички типове, полета, функции и т.н. са private

Структури

Ниво на достъп

По подразбиране, всички типове, полета, функции и т.н. са private

В Rust

Структури

Ниво на достъп

По подразбиране, всички типове, полета, функции и т.н. са private

В Rust

Структури

Ниво на достъп

По подразбиране, всички типове, полета, функции и т.н. са private

В Rust

Eдин модул обикновенно съответства на един файл

Структури

Ниво на достъп

По подразбиране, всички типове, полета, функции и т.н. са private

В Rust

Eдин модул обикновенно съответства на един файл

Структури

Ниво на достъп

За да напраивм нещо публично достъпно, трябва да използвам ключовата дума pub

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
pub struct User {
    pub username: String,
    pub email: String,
    sign_in_count: u32,
}

impl User {
    pub fn new(username: String, email: String) -> User {
        User { username, email, sign_in_count: 0 }
    }

    pub fn check_and_sign_in(&mut self) -> bool {
        /* ... */
    }
}
pub struct User {
    pub username: String,
    pub email: String,
    sign_in_count: u32,
}

impl User {
    pub fn new(username: String, email: String) -> User {
        User { username, email, sign_in_count: 0 }
    }

    pub fn check_and_sign_in(&mut self) -> bool {
        /* ... */
todo!()
    }
}
fn main() {}

Структури

getters and setters

Структури

getters and setters

Структури

getters and setters

Структури

getters and setters

Структури

getters and setters

Структури

getters and setters

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
struct Rectangle {
    width: f64,
    height: f64,
    precomputed_area: f64,
}

impl Rectangle {
    pub fn width(&self) -> f64 {
        self.width
    }

    pub fn set_width(&mut self, width: f64) {
        self.width = width;
        self.precomputed_area = self.height * self.width;
    }

    pub fn area(&self) -> f64 {
        self.precomputed_area
    }
}
struct Rectangle {
    width: f64,
    height: f64,
    precomputed_area: f64,
}

impl Rectangle {
    pub fn width(&self) -> f64 {
        self.width
    }

    pub fn set_width(&mut self, width: f64) {
        self.width = width;
        self.precomputed_area = self.height * self.width;
    }

    pub fn area(&self) -> f64 {
        self.precomputed_area
    }
}
fn main() {}

Структури

getters and setters

Това е възможно, защото полетата и методите използват различни полета от имена

1 2 3 4 5 6 7 8 9 10 11 12
struct Rectangle { width: f64 }

impl Rectangle {
    pub fn width(&self) -> f64 { self.width }
}

// полето width
rect.width

// метода width
rect.width()
Rect::width

Структури

getters and setters

Това е възможно, защото полетата и методите използват различни полета от имена

1 2 3 4 5 6 7 8 9 10 11 12
struct Rectangle { width: f64 }

impl Rectangle {
    pub fn width(&self) -> f64 { self.width }
}

// полето width
rect.width

// метода width
rect.width()
Rect::width

В по-редкия случай, когато полето е от тип фунцкия, се използват допълнителни скоби

1
(my_struct.f)()

Структури

getters and setters

Забележка - не прекалявайте с getter-и и setter-и

Структури

getters and setters

Забележка - не прекалявайте с getter-и и setter-и

Структури

getters and setters

Забележка - не прекалявайте с getter-и и setter-и

Структури

getters and setters

Забележка - не прекалявайте с getter-и и setter-и

Структури

getters and setters

Забележка - не прекалявайте с getter-и и setter-и

Структури

getters and setters

Забележка - не прекалявайте с getter-и и setter-и



Има аргумент, че скриването на полета зад getter-и и setter-и позволява да се променя memory layout-а на структурата (да се добавят или премахват полета), без да се афектира публичния интерфейс.

Структури

getters and setters

Забележка - не прекалявайте с getter-и и setter-и



Има аргумент, че скриването на полета зад getter-и и setter-и позволява да се променя memory layout-а на структурата (да се добавят или премахват полета), без да се афектира публичния интерфейс.

Структури

getters and setters

Забележка - не прекалявайте с getter-и и setter-и



Има аргумент, че скриването на полета зад getter-и и setter-и позволява да се променя memory layout-а на структурата (да се добавят или премахват полета), без да се афектира публичния интерфейс.

Празни структури

Възможна е декларация на структури без полета.
Големината им е 0 байта.

1 2 3 4 5
struct Proton {}
struct Electron;

let x = Proton {};
let y = Electron;
fn main() {
struct Proton {}
struct Electron;

let x = Proton {};
let y = Electron;
}

Tuples

Tuples

(преговор)

1 2 3 4 5
let tuple: (i32, u32, bool) = (1, 2, false);

println!("{}", tuple.0);
println!("{}", tuple.1);
println!("{}", tuple.2);
1 2 false
fn main() {
let tuple: (i32, u32, bool) = (1, 2, false);

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

Tuple structs

Именувани кортежи

1 2 3 4 5
struct Color(f32, f32, f32);
struct Point(f32, f32, f32);

let black = Color(0.0, 0.0, 0.0);
let origin = Point(0.0, 0.0, 0.0);
fn main() {
struct Color(f32, f32, f32);
struct Point(f32, f32, f32);

let black = Color(0.0, 0.0, 0.0);
let origin = Point(0.0, 0.0, 0.0);
}

Tuple structs

Полетата се достъпват с .0, .1, и т.н., както при нормален tupple

1 2 3 4 5
struct Color(f32, f32, f32);

let black = Color(0.0, 0.0, 0.0);

println!("r: {}, g: {}, b: {}", black.0, black.1, black.2);
r: 0, g: 0, b: 0
fn main() {
struct Color(f32, f32, f32);

let black = Color(0.0, 0.0, 0.0);

println!("r: {}, g: {}, b: {}", black.0, black.1, black.2);
}

Tuple structs

Ниво на достъп

Полетата в tuple struct също са private по подразбиране.
За да могат да се достъпват отвън, трябва да се декларират с pub.

1
pub struct Color(pub f32, pub f32, pub f32);
fn main() {
pub struct Color(pub f32, pub f32, pub f32);
}

Tuple structs

Newtype wrapper

Tuple struct с едно поле често се използва за typesafe wrapper.
Това се нарича newtype.

1 2
#[derive(Debug, Clone, Copy)]
struct Token(u32);
#[derive(Debug, Clone, Copy)]
struct Token(u32);

fn main() {}

Tuple structs

Разлика между type alias и newtype

1
type Node<T> = Rc<RefCell<TreeNode<T>>>;
use std::rc::Rc;
use std::cell::RefCell;
struct TreeNode { x: T }
fn main() {}
type Node = Rc>>;

Tuple structs

Разлика между type alias и newtype

1 2 3 4 5 6 7 8 9
struct UserId(pub u32);

fn find_user(id: UserId) {}

// let id = 10;
// find_user(id); // error

let id = UserId(10);
find_user(id); // ok
fn main() {
struct UserId(pub u32);

fn find_user(id: UserId) {}

// let id = 10;
// find_user(id); // error

let id = UserId(10);
find_user(id); // ok
}

Enums

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

Защо?

1
struct User { username: String, email: String, sign_in_count: u64 }

Enums

Защо?

1
struct User { username: String, email: String, sign_in_count: u64 }

Enums

Защо?

1 2 3 4
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}
fn main() {}
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

Enums

Защо?

1 2 3 4
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}
fn main() {}
enum IpAddr {
    V4(u8, u8, u8, u8),
    V6(String),
}

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
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

Защо?

Чрез enum можем да изразим всички валидни стойности чрез типовата система

Enums

Защо?

Чрез enum можем да изразим всички валидни стойности чрез типовата система

Make invalid states unrepresentable

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? Ще видим след няколко слайда :)

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

Вариант Памет

Message::Quit

Message::Move { x: i64, y: i64 }

Message::Write(String)

Message::ChangeColor(i64, i64, i64)

+–––––––++–––––––––––––––––––––––+
│   0   ││                       │
+–––––––++–––––––+–––––––+–––––––+
│   1   ││  i64  │  i64  │       │
+–––––––++–––––––+–––––––+–––––––+
│   2   ││       String          │
+–––––––++–––––––+–––––––+–––––––+
│   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::());
}

C-like enum

1 2 3 4 5 6 7 8 9 10 11
#[derive(Debug)]
#[repr(i32)]
enum Basic {
    A = 0,
    B = 12,
}

fn main() {
    println!("{:?}", Basic::B);
    println!("{:?}", Basic::B as i32);
}
B 12
#[derive(Debug)]
#[repr(i32)]
enum Basic {
    A = 0,
    B = 12,
}

fn main() {
    println!("{:?}", Basic::B);
    println!("{:?}", Basic::B as i32);
}

C-like enum

1 2 3 4 5 6 7 8 9 10 11 12
#[derive(Debug)]
#[repr(i32)]
enum Basic {
    A = 0,
    B = 12,
}

fn main() {
    println!("{:?}", Basic::B);
    println!("{:?}", Basic::B as i32);
    println!("{:?}", 12 as Basic);
}
error[E0605]: non-primitive cast: `i32` as `Basic` --> src/bin/main_bc0a03e54fa3ae812422d0cb1fca065483329aaa.rs:11:22 | 11 | println!("{:?}", 12 as Basic); | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object For more information about this error, try `rustc --explain E0605`. error: could not compile `rust` (bin "main_bc0a03e54fa3ae812422d0cb1fca065483329aaa") due to 1 previous error
#[derive(Debug)]
#[repr(i32)]
enum Basic {
    A = 0,
    B = 12,
}

fn main() {
    println!("{:?}", Basic::B);
    println!("{:?}", Basic::B as i32);
    println!("{:?}", 12 as Basic);
}

C-like enum

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#[derive(Debug)]
#[repr(i32)]
enum Basic {
    A = 0,
    B = 12,
}

impl Basic {
    fn from_i32(i: i32) -> Basic {
        if i == 0 {
            Basic::A
        } else if i == 12 {
            Basic::B
        } else {
            _ => panic!("грешка!"),
        }
    }
}

fn main() {
    println!("{:?}", Basic::from_i32(12));
}
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `=>` --> src/bin/main_0b858b35302dd1654ab2355517db7d7cc9ee1839.rs:15:15 | 15 | _ => panic!("грешка!"), | ^^ expected one of `.`, `;`, `?`, `}`, or an operator | help: you might have meant to write a "greater than or equal to" comparison | 15 - _ => panic!("грешка!"), 15 + _ >= panic!("грешка!"), | error: could not compile `rust` (bin "main_0b858b35302dd1654ab2355517db7d7cc9ee1839") due to 1 previous error
#[derive(Debug)]
#[repr(i32)]
enum Basic {
    A = 0,
    B = 12,
}

impl Basic {
    fn from_i32(i: i32) -> Basic {
        if i == 0 {
            Basic::A
        } else if i == 12 {
            Basic::B
        } else {
            _ => panic!("грешка!"),
        }
    }
}

fn main() {
    println!("{:?}", Basic::from_i32(12));
}

Pattern Matching

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

Pattern Matching

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

Pattern Matching

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

Pattern Matching

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

Pattern Matching

1 2 3 4 5 6 7 8 9 10 11 12 13
impl Message {
    fn call(&self) {
        match self {
            Message::Quit => println!("got quit"),
            Message::Move {x, y} => println!("got move {x}, {y}"),
            Message::Write(s) => println!("got write {s:?}"),
            Message::ChangeColor(r, g, b) => println!("got change_color {r}, {g}, {b}"),
        }
    }
}

let m = Message::Write(String::from("hello"));
m.call();
got write "hello"
fn main() {
enum Message {
Quit,
Move { x: i64, y: i64 },
Write(String),
ChangeColor(i64, i64, i64),
}

impl Message {
    fn call(&self) {
        match self {
            Message::Quit => println!("got quit"),
            Message::Move {x, y} => println!("got move {x}, {y}"),
            Message::Write(s) => println!("got write {s:?}"),
            Message::ChangeColor(r, g, b) => println!("got change_color {r}, {g}, {b}"),
        }
    }
}

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

Pattern Matching

1 2 3 4 5
match value {
    PATTERN1 => expr1,
    PATTERN2 => expr2,
    PATTERN3 => expr3,
}

Pattern Matching

1 2 3 4 5
match value {
    PATTERN1 => expr1,
    PATTERN2 => expr2,
    PATTERN3 => expr3,
}

Pattern Matching

1 2 3 4 5
match value {
    PATTERN1 => expr1,
    PATTERN2 => expr2,
    PATTERN3 => expr3,
}

Pattern Matching

1 2 3 4 5
match value {
    PATTERN1 => expr1,
    PATTERN2 => expr2,
    PATTERN3 => expr3,
}

Pattern Matching

1 2 3 4 5
match value {
    PATTERN1 => expr1,
    PATTERN2 => expr2,
    PATTERN3 => expr3,
}

Pattern Matching

Може да се съпоставя по стойност

1 2 3 4 5
let condition = true;
match condition {
    true => println!("it's ok"),
    false => println!("it's bad"),
}
it's ok
fn main() {
let condition = true;
match condition {
    true => println!("it's ok"),
    false => println!("it's bad"),
}
}

Pattern Matching

Образеца _ отговаря на всяка възможна стойност

1 2 3 4 5 6 7
let my_number = 14;
match my_number {
    1 => println!("it's one"),
    2 => println!("it's two"),
    3 => println!("it's three"),
    _ => println!("it's something else"),
}
it's something else
fn main() {
let my_number = 14;
match my_number {
    1 => println!("it's one"),
    2 => println!("it's two"),
    3 => println!("it's three"),
    _ => println!("it's something else"),
}
}

Pattern Matching

Може да се сравнява с интервали от стойности

1 2 3 4 5 6 7
let my_number = 14_u32;
match my_number {
    0 => println!("none"),
    1..3 => println!("small"),
    3..=14 => println!("medium"),
    15.. => println!("large"),
}
medium
fn main() {
let my_number = 14_u32;
match my_number {
    0 => println!("none"),
    1..3 => println!("small"),
    3..=14 => println!("medium"),
    15.. => println!("large"),
}
}

Pattern Matching

Съвпадналата стойност може да бъде присвоена на променлива с @

1 2 3 4 5 6 7
let my_number = 14_u32;
match my_number {
    0 => println!("none"),
    n @ 1..3 => println!("{n} is small"),
    n @ 3..=14 => println!("{n} is medium"),
    15.. => println!("too large"),
}
14 is medium
fn main() {
let my_number = 14_u32;
match my_number {
    0 => println!("none"),
    n @ 1..3 => println!("{n} is small"),
    n @ 3..=14 => println!("{n} is medium"),
    15.. => println!("too large"),
}
}

Pattern Matching

Име (identifier) съвпада на всяка стойност и присвоява стойността на променлива с това име. Все едно var @ _.

1 2 3 4 5 6 7
let my_number = 14_u32;
match my_number {
    0 => println!("none"),
    n @ 1..3 => println!("{n} is small"),
    n @ 3..=14 => println!("{n} is medium"),
    n => println!("{n} is too large"),
}
14 is medium
fn main() {
let my_number = 14_u32;
match my_number {
    0 => println!("none"),
    n @ 1..3 => println!("{n} is small"),
    n @ 3..=14 => println!("{n} is medium"),
    n => println!("{n} is too large"),
}
}

Pattern Matching

Име в образен винаги създава нова променлива, която засенчва съществуващи променливи.
Не може да се използва за съпоставяне със стойността на съществуваща променлива

1 2 3 4 5 6 7
#![allow(unreachable_patterns)]

let x = 5;
match 123 {
    x => println!("it should be five; got x={x}"), // wrong
    _ => println!("it's not five"), // wrong
}
it should be five; got x=123
#![allow(unreachable_patterns)]

fn main() {
let x = 5;
match 123 {
    x => println!("it should be five; got x={x}"), // wrong
    _ => println!("it's not five"), // wrong
}
}

Pattern Matching

Име в образен винаги създава нова променлива, която засенчва съществуващи променливи.
Не може да се използва за съпоставяне със стойността на съществуваща променлива

1 2 3 4 5 6 7
// #![allow(unreachable_patterns)]

let x = 5;
match 123 {
    x => println!("it should be five; got x={x}"), // wrong
    _ => println!("it's not five"), // wrong
}
warning: unreachable pattern --> src/bin/main_0992ff311fb9eb93ad5bdedc2e5e35d62833f5ba.rs:7:5 | 6 | x => println!("it should be five; got x={x}"), // wrong | - matches any value 7 | _ => println!("it's not five"), // wrong | ^ no value can reach this | note: there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings --> src/bin/main_0992ff311fb9eb93ad5bdedc2e5e35d62833f5ba.rs:4:5 | 4 | let x = 5; | ^ = note: `#[warn(unreachable_patterns)]` on by default
fn main() {
let x = 5;
match 123 {
    x => println!("it should be five; got x={x}"), // wrong
    _ => println!("it's not five"), // wrong
}
}

Pattern Matching

1 2 3 4 5 6 7 8 9 10
enum FooBar {
    Foo,
    Bar,
}

let val = FooBar::Foo;
match val {
    FooBar::Foo => println!("it's foo"),
    FooBar::Bar => println!("it's bar"),
}
it's foo
fn main() {
enum FooBar {
    Foo,
    Bar,
}

let val = FooBar::Foo;
match val {
    FooBar::Foo => println!("it's foo"),
    FooBar::Bar => println!("it's bar"),
}
}

Pattern Matching

1 2 3 4 5 6 7
let coords = (3, 3);
match coords {
    (0, 0) => println!("center"),
    (0, y) => println!("vertical {y}"),
    (x, 0) => println!("horizontal {x}"),
    (x, y) => println!("nowhere in particular {x},{y}"),
}
nowhere in particular 3,3
fn main() {
let coords = (3, 3);
match coords {
    (0, 0) => println!("center"),
    (0, y) => println!("vertical {y}"),
    (x, 0) => println!("horizontal {x}"),
    (x, y) => println!("nowhere in particular {x},{y}"),
}
}

Pattern Matching

Съпоставяне на масиви и резени

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!")
}
}

Pattern Matching

.. отговаря на всичко останало от масива

1 2 3 4 5 6
let nums = &[1, 2, 3][..];
match nums {
    [] => println!("empty"),
    [a] => println!("just {a}"),
    [x, ..] => println!("head is {x}"),
}
head is 1
fn main() {
let nums = &[1, 2, 3][..];
match nums {
    [] => println!("empty"),
    [a] => println!("just {a}"),
    [x, ..] => println!("head is {x}"),
}
}

Pattern Matching

.. може да се комбинира с @

1 2 3 4 5 6
let nums = &[1, 2, 3][..];
match nums {
    [] => println!("empty"),
    [a] => println!("just {a}"),
    [x, rest @ ..] => println!("head is {x}, tail is {rest:?}"),
}
head is 1, tail is [2, 3]
fn main() {
let nums = &[1, 2, 3][..];
match nums {
    [] => println!("empty"),
    [a] => println!("just {a}"),
    [x, rest @ ..] => println!("head is {x}, tail is {rest:?}"),
}
}

Pattern Matching

.. работи и в началото или средата.

1 2 3 4 5 6
let nums = &[1, 2, 3, 4][..];
match nums {
    [] => println!("empty"),
    [a] => println!("just {a}"),
    [first, mid @ .., last] => println!("{first} then {mid:?} then {last}"),
}
1 then [2, 3] then 4
fn main() {
let nums = &[1, 2, 3, 4][..];
match nums {
    [] => println!("empty"),
    [a] => println!("just {a}"),
    [first, mid @ .., last] => println!("{first} then {mid:?} then {last}"),
}
}

Pattern Matching

Но може да се среща само веднъж в целия образец

1 2 3 4 5 6
let nums = &[1, 2, 3, 4][..];
match nums {
    [] => println!("empty"),
    [a] => println!("just {a}"),
    [.., mid, ..] => println!("mid is {mid}"),
}
error: `..` can only be used once per slice pattern --> src/bin/main_cc2e630a367d1ea68231c8d5466227007d241c57.rs:6:15 | 6 | [.., mid, ..] => println!("mid is {mid}"), | -- ^^ can only be used once per slice pattern | | | previously used here error: could not compile `rust` (bin "main_cc2e630a367d1ea68231c8d5466227007d241c57") due to 1 previous error
fn main() {
let nums = &[1, 2, 3, 4][..];
match nums {
    [] => println!("empty"),
    [a] => println!("just {a}"),
    [.., mid, ..] => println!("mid is {mid}"),
}
}

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!("Нищо интересно"),
}
fn main() {
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

Алтернативност

Няколко алтернативни образци могат да бъдат сложени в един ръкав, разделени с |.
Ще бъдат пробвани от ляво надясно. Променливи могат да се прихващат, стига да присъстват във всеки образец и да са от един и същи тип.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
enum FooBar {
    Foo(u32),
    Bar(u32),
}

let val = FooBar::Bar(13);
match val {
    FooBar::Foo(10) | FooBar::Bar(10) => {
        println!("десетка");
    }
    FooBar::Foo(n @ 0..=9) | FooBar::Bar(n) => {
        println!("малък фуу или бар: {n}");
    }
    FooBar::Foo(_) => {
        println!("голям фуу");
    }
}
малък фуу или бар: 13
fn main() {
enum FooBar {
    Foo(u32),
    Bar(u32),
}

let val = FooBar::Bar(13);
match val {
    FooBar::Foo(10) | FooBar::Bar(10) => {
        println!("десетка");
    }
    FooBar::Foo(n @ 0..=9) | FooBar::Bar(n) => {
        println!("малък фуу или бар: {n}");
    }
    FooBar::Foo(_) => {
        println!("голям фуу");
    }
}
}

Pattern Matching

Алтернативност

Интересен факт - позволено е да се добави символ | в началото на ръкава, който не прави нищо.
Но позволява кода да се подреди по този начин.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
enum FooBar {
    Foo(u32),
    Bar(u32),
}

let val = FooBar::Bar(13);
match val {
    | FooBar::Foo(10)
    | FooBar::Bar(10) => {
        println!("десетка");
    }
    | FooBar::Foo(n @ 0..=9)
    | FooBar::Bar(n)  => {
        println!("малък фуу или бар: {n}");
    }
    FooBar::Foo(_) => {
        println!("голям фуу");
    }
}
малък фуу или бар: 13
fn main() {
enum FooBar {
    Foo(u32),
    Bar(u32),
}

let val = FooBar::Bar(13);
match val {
    | FooBar::Foo(10)
    | FooBar::Bar(10) => {
        println!("десетка");
    }
    | FooBar::Foo(n @ 0..=9)
    | FooBar::Bar(n)  => {
        println!("малък фуу или бар: {n}");
    }
    FooBar::Foo(_) => {
        println!("голям фуу");
    }
}
}

Pattern Matching

Ограничения - типовете трябва да съответстват

1 2 3 4 5 6 7 8 9 10 11 12
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, .. }             => println!("Ко стаа, {name}"),
}
Ко стаа, Пешо
fn main() {
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, .. }             => println!("Ко стаа, {name}"),
}
}

Pattern Matching

Ограничения - типовете трябва да съответстват

1 2 3 4 5 6 7 8 9 10 11 12
struct User {
    name: String,   // <- низ със собственост
    age: u8
}

let user = User { name: "Пешо", age: 12 };

match user {            // не е ок
    User { name: "Пешо", age: _ } => println!("Ко стаа, Пешо"),
    User { name: _, age: 12 }     => println!("Ко стаа, лапе"),
    User { name, .. }             => println!("Ко стаа, {name}"),
}
error[E0308]: mismatched types --> src/bin/main_439783a543372c3358cdb023d2fa310f5cf4e04c.rs:7:25 | 7 | let user = User { name: "Пешо", age: 12 }; | ^^^^^^ expected `String`, found `&str` | help: try using a conversion method | 7 | let user = User { name: "Пешо".to_string(), age: 12 }; | ++++++++++++ error[E0308]: mismatched types --> src/bin/main_439783a543372c3358cdb023d2fa310f5cf4e04c.rs:10:18 | 9 | match user { // не е ок | ---- this expression has type `User` 10 | User { name: "Пешо", age: _ } => println!("Ко стаа, Пешо"), | ^^^^^^ expected `String`, found `&str` For more information about this error, try `rustc --explain E0308`. error: could not compile `rust` (bin "main_439783a543372c3358cdb023d2fa310f5cf4e04c") due to 2 previous errors
fn main() {
struct User {
    name: String,   // <- низ със собственост
    age: u8
}

let user = User { name: "Пешо", age: 12 };

match user {            // не е ок
    User { name: "Пешо", age: _ } => println!("Ко стаа, Пешо"),
    User { name: _, age: 12 }     => println!("Ко стаа, лапе"),
    User { name, .. }             => println!("Ко стаа, {name}"),
}
}

Destructuring

Destructuring

let bindings

Повечето от образците, поддържани от match, могат да се използват и за разбиране на стойност в let клаузи.
Дясната страна трябва винаги да може да се съпостави на лявата - irrefutable binding.

1 2 3 4 5 6 7
let (a, b, c) = (1, true, "three");
let (a, ..) = (1, true, "three");
let (.., c) = (1, true, "three");

let [a, b, c] = [1, 2, 3];
let [a, ..] = [1, 2, 3];
let [.., c] = [1, 2, 3];
fn main() {
let (a, b, c) = (1, true, "three");
let (a, ..) = (1, true, "three");
let (.., c) = (1, true, "three");

let [a, b, c] = [1, 2, 3];
let [a, ..] = [1, 2, 3];
let [.., c] = [1, 2, 3];
}

Destructuring

let bindings

Повечето от образците, поддържани от match, могат да се използват и за разбиране на стойност в let клаузи.
Дясната страна трябва винаги да може да се съпостави на лявата - irrefutable binding.

1 2 3 4 5
let User { name: name_var, .. } = user;
println!("{}", name_var);

let User { name, .. } = user;
println!("{}", name);
fn main() {
#[derive(Default)] struct User { name: String, email: String }
let user = User::default();
let User { name: name_var, .. } = user;
println!("{}", name_var);

let user = User::default();
let User { name, .. } = user;
println!("{}", name);
}

More control flow

if let

1 2 3
if let PATTERN = value {
    code()
}

Еквиваленто на долния match.
Но спестява едно ниво на индентация и няколко реда

1 2 3 4 5 6
match value {
    PATTERN => {
        code()
    }
    _ => {}
}

More control flow

while let

А защо не и while let:

1 2 3
while let PATTERN = expr() {
    code()
}

Еквивалентно на

1 2 3 4 5 6 7 8 9 10
loop {
    match expr() {
        PATTERN => {
            code()
        }
        _ => {
            break
        }
    }
}

Option

Option

Option

Option

Option

Option

Option

При възможност за липсваща стойност се използва Option.
Има 2 стойности:

1 2 3 4
enum Option<T> {
    Some(T),
    None,
}
fn main() {}
enum Option {
    Some(T),
    None,
}

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

Option

Non-zero оптимизация

За много типове нула/null е невалидна стойност.
Или съдържат поле, за което е невалидна стойност (напр ptr в String).

Ако такъв тип се използва в enum, компилатора може да използва свободния слот, за да помести другите варианти.

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

Option

Non-zero оптимизация

Това много често се случва при Option.
При всички тези случаи Option е zero cost abstraction.

1 2 3 4 5 6 7 8 9
use std::mem;
fn main() {
    println!("&T:            {:?} vs {:?}", mem::size_of::<&u32>(), mem::size_of::<Option<&u32>>());
    println!("Box<T>:        {:?} vs {:?}", mem::size_of::<Box<u32>>(), mem::size_of::<Option<Box<u32>>>());
    println!("&str:          {:?} vs {:?}", mem::size_of::<&str>(), mem::size_of::<Option<&str>>());
    println!("String:        {:?} vs {:?}", mem::size_of::<String>(), mem::size_of::<Option<String>>());
    println!("Vec<_>:        {:?} vs {:?}", mem::size_of::<Vec<u32>>(), mem::size_of::<Option<Vec<u32>>>());
    println!("HashMap<_, _>: {:?} vs {:?}", mem::size_of::<HashMap<u32, u32>>(), mem::size_of::<Option<HashMap<u32, u32>>>());
}
&T: 8 vs 8 Box<T>: 8 vs 8 &str: 16 vs 16 String: 24 vs 24 Vec<_>: 24 vs 24 HashMap<_, _>: 48 vs 48
use std::collections::HashMap;
use std::mem;
fn main() {
    println!("&T:            {:?} vs {:?}", mem::size_of::<&u32>(), mem::size_of::>());
    println!("Box:        {:?} vs {:?}", mem::size_of::>(), mem::size_of::>>());
    println!("&str:          {:?} vs {:?}", mem::size_of::<&str>(), mem::size_of::>());
    println!("String:        {:?} vs {:?}", mem::size_of::(), mem::size_of::>());
    println!("Vec<_>:        {:?} vs {:?}", mem::size_of::>(), mem::size_of::>>());
    println!("HashMap<_, _>: {:?} vs {:?}", mem::size_of::>(), mem::size_of::>>());
}

Result

Друг много често срещан тип е Result.
В Rust няма exceptions - функции които могат да се провалят връщат Result

1 2 3 4
enum Result<T, E> {
    Ok(T),
    Err(E),
}
fn main() {}
enum Result {
    Ok(T),
    Err(E),
}

Option и Result

Извличане на стойност

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

let double = match some_number {
    Some(val) => val + val,
    None => 0,
};

println!("{:?}", double);
10
fn main() {
let some_number = Some(5);

let double = match some_number {
    Some(val) => val + val,
    None => 0,
};

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

Option и Result

Извличане на стойност

Option и Result

Извличане на стойност

Option и Result

Извличане на стойност

Option и Result

Извличане на стойност

Option и Result

Извличане на стойност

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

let val = some_number.unwrap();
let double =  val + val;
println!("{:?}", double);
10
fn main() {
let some_number = Some(5);

let val = some_number.unwrap();
let double =  val + val;
println!("{:?}", double);
}

Итерация

Итерация

1 2 3 4 5
let numbers = vec![11, 22, 33, 44, 55];

for n in numbers.iter() {
    print!("{} ", n);
}
11 22 33 44 55
fn main() {
let numbers = vec![11, 22, 33, 44, 55];

for n in numbers.iter() {
    print!("{} ", n);
}
println!();
}

Итерация

1 2 3
for c in "Здравей! 😊" {
    // ...
}
error[E0277]: `&str` is not an iterator --> src/bin/main_d4d96cd45194a2a7f7b2fdd29a913a03c9c66432.rs:2:10 | 2 | for c in "Здравей! 😊" { | ^^^^^^^^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` | = help: the trait `Iterator` is not implemented for `&str` = note: required for `&str` to implement `IntoIterator` For more information about this error, try `rustc --explain E0277`. error: could not compile `rust` (bin "main_d4d96cd45194a2a7f7b2fdd29a913a03c9c66432") due to 1 previous error
fn main() {
for c in "Здравей! 😊" {
    // ...
}
}

Итерация

1 2 3
for b in "Здравей! 😊".bytes() {
    print!("{:02x} ", b);
}
d0 97 d0 b4 d1 80 d0 b0 d0 b2 d0 b5 d0 b9 21 20 f0 9f 98 8a
fn main() {
for b in "Здравей! 😊".bytes() {
    print!("{:02x} ", b);
}
println!();
}

Итерация

1 2 3
for c in "Здравей! 😊".chars() {
    print!("{:?} ", c);
}
'З' 'д' 'р' 'а' 'в' 'е' 'й' '!' ' ' '😊'
fn main() {
for c in "Здравей! 😊".chars() {
    print!("{:?} ", c);
}
println!();
}

Итерация

1 2 3
for s in "Здравей свят! 😊".split_whitespace() {
    println!("{:?} ", s);
}
"Здравей" "свят!" "😊"
fn main() {
for s in "Здравей свят! 😊".split_whitespace() {
    println!("{:?} ", s);
}
println!();
}

Итерация

1 2 3
for value in iterator {
    code
}

Итерация

1 2 3
for value in iterator {
    code
}

Итерация

1 2 3
for value in iterator {
    code
}
1 2 3 4 5
trait Iterator {
    type Item;

    fn next(&mut self) -> Option<Self::Item>;
}
fn main() {}
trait Iterator {
    type Item;

    fn next(&mut self) -> Option;
}

Итерация

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

Итерация

1 2 3 4 5 6
let mut words = "one two three".split_whitespace(); // std::str::SplitWhitespace

println!("{:?}", words.next());
println!("{:?}", words.next());
println!("{:?}", words.next());
println!("{:?}", words.next());
Some("one") Some("two") Some("three") None
fn main() {
let mut words = "one two three".split_whitespace(); // std::str::SplitWhitespace

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

Итерация

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
for word in "one two three".split_whitespace() {
    println!("{}", word);
}

// приблизителен desugaring
{
    let mut iter = "one two three".split_whitespace();
    loop {
        match iter.next() {
            Some(word) => {
                println!("{}", word);
            },
            None => {
                break;
            }
        }
    }
}
fn main() {
for word in "one two three".split_whitespace() {
    println!("{}", word);
}

// приблизителен desugaring
{
    let mut iter = "one two three".split_whitespace();
    loop {
        match iter.next() {
            Some(word) => {
                println!("{}", word);
            },
            None => {
                break;
            }
        }
    }
}
}

Итерация

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
for word in "one two three".split_whitespace() {
    println!("{}", word);
}

// малко по-точен desugaring
{
    let mut iter = ("one two three".split_whitespace()).into_iter();
    loop {
        match iter.next() {
            Some(word) => {
                println!("{}", word);
            },
            None => {
                break;
            }
        }
    }
}
fn main() {
for word in "one two three".split_whitespace() {
    println!("{}", word);
}

// малко по-точен desugaring
{
    let mut iter = ("one two three".split_whitespace()).into_iter();
    loop {
        match iter.next() {
            Some(word) => {
                println!("{}", word);
            },
            None => {
                break;
            }
        }
    }
}
}

Итерация

Итерация

1 2 3 4 5 6 7 8 9 10 11 12
for word in "one two three".split_whitespace() {
    println!("{}", word);
}

// захаросан desugaring ??
{
    let mut iter = ("one two three".split_whitespace()).into_iter();

    while let Some(word) = iter.next() {
        println!("{}", word);
    }
}
fn main() {
for word in "one two three".split_whitespace() {
    println!("{}", word);
}

// захаросан desugaring ??
{
    let mut iter = ("one two three".split_whitespace()).into_iter();

    while let Some(word) = iter.next() {
        println!("{}", word);
    }
}
}

Итерация

Пример

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

Итерация

IntoIterator

1 2 3 4 5 6 7 8 9
let numbers = vec![11, 22, 33, 44, 55];

for num in &numbers[..] {
}

// vs

for num in numbers.iter() {
}
fn main() {
let numbers = vec![11, 22, 33, 44, 55];

for num in &numbers[..] {
}

// vs

for num in numbers.iter() {
}
}

Итерация

IntoIterator

1 2 3 4 5 6 7
x.iter()
// е еквивалентно на
(&x).into_iter()

x.iter_mut()
// е еквиваленто на
(&mut x).into_iter()

Итерация

IntoIterator

израз тип на итератора
for x in &[1, 2, 3] std::slice::Iter
for x in [1, 2, 3].iter() std::slice::Iter
for x in &vec![1, 2, 3] std::slice::Iter
for x in vec![1, 2, 3].iter() std::slice::Iter
for x in &mut [1, 2, 3] std::slice::IterMut
for x in [1, 2, 3].iter_mut() std::slice::IterMut

Методи на итератори

Методи на итератори

Методи на итератори

Методи на итератори

Методи на итератори

Методи на итератори

Методи на итератори

Методи на итератори

1 2 3 4
let text = "Здравей! 😊";
let text_chars: Vec<char> = text.chars().collect();

println!("{:?}", text_chars);
['З', 'д', 'р', 'а', 'в', 'е', 'й', '!', ' ', '😊']
fn main() {
let text = "Здравей! 😊";
let text_chars: Vec = text.chars().collect();

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

Методи на итератори

1 2 3 4
let text = "Здравей! 😊";
let text_chars: Vec<_> = text.chars().collect();
            //     ^^^
println!("{:?}", text_chars);
['З', 'д', 'р', 'а', 'в', 'е', 'й', '!', ' ', '😊']
fn main() {
let text = "Здравей! 😊";
let text_chars: Vec<_> = text.chars().collect();
            //     ^^^
println!("{:?}", text_chars);
}

Методи на итератори

Методи на итератори

Методи на итератори

Методи на итератори

Методи на итератори

Методи на итератори

Въпроси