Structs, enums, pattern matching

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

15 октомври 2024

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Административни неща

Административни неща

Структури

Структури

Синтаксис

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 12 13
struct User {
    username: String,
    email: String,
    sign_in_count: u64
}

fn main() {
    let user = User {
        username: String::from("Иванчо"),
        email: String::from("ivan40@abv.bg"),
        sign_in_count: 10,
    };
}
struct User {
    username: String,
    email: String,
    sign_in_count: u64
}

fn main() {
    let user = User {
        username: String::from("Иванчо"),
        email: String::from("ivan40@abv.bg"),
        sign_in_count: 10,
    };
}

Структури

Създаване на инстанция

Има кратък синтаксис за задаване на поле чрез променлива със същото име.

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

let username = String::from("Иванчо");
let email = String::from("ivan40@abv.bg");
let sign_in_count = 10;

// пълен синтаксис
let user = User {
    username: username,
    email: email,
    sign_in_count: sign_in_count,
};

// кратък синтаксис
let user = User { username, email, sign_in_count };

Структури

Достъп до полета

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

let user = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

println!("{}, {}", user.username, user.email);
Иванчо, ivan40@abv.bg
fn main() {
struct User {
    username: String,
    email: String,
    sign_in_count: u64
}

let user = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

println!("{}, {}", user.username, user.email);
}

Структури

Достъп до полета

Полетата се достъпват по същия начин и през референция.
Автоматично се правят необходимия брой дереференцирания.

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

let user = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let user_ref = &user;

println!("{}, {}", user_ref.username, user_ref.email);
Иванчо, ivan40@abv.bg
fn main() {
struct User {
    username: String,
    email: String,
    sign_in_count: u64
}

let user = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let user_ref = &user;

println!("{}, {}", user_ref.username, user_ref.email);
}

Структури

Промяна на полетата

Можем да променяме стойността на полетата, ако инстанцията е дефинирана като mut.

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

let mut user = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

user.email = "ivan40.ivanov@abv.bg".to_string();

println!("{}, {}", user.username, user.email);
Иванчо, ivan40.ivanov@abv.bg
fn main() {
struct User {
    username: String,
    email: String,
    sign_in_count: u64
}

let mut user = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

user.email = "ivan40.ivanov@abv.bg".to_string();

println!("{}, {}", user.username, user.email);
}

Структури

Преместване на структури

По подразбиране структурите се преместват (защото не имплементират Copy).

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

let user1 = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let user2 = user1;

println!("user1 = {}, {}", user1.username, user1.email);
println!("user2 = {}, {}", user2.username, user2.email);
error[E0382]: borrow of moved value: `user1` --> src/bin/main_b3c03fba678cada8014f8bd9534eee85648a700d.rs:16:44 | 8 | let user1 = User { | ----- move occurs because `user1` has type `User`, which does not implement the `Copy` trait ... 14 | let user2 = user1; | ----- value moved here 15 | 16 | println!("user1 = {}, {}", user1.username, user1.email); | ^^^^^^^^^^^ value borrowed here after move | note: if `User` implemented `Clone`, you could clone the value --> src/bin/main_b3c03fba678cada8014f8bd9534eee85648a700d.rs:2:1 | 2 | struct User { | ^^^^^^^^^^^ consider implementing `Clone` for this type ... 14 | let user2 = user1; | ----- you could clone this value = 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) For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` (bin "main_b3c03fba678cada8014f8bd9534eee85648a700d") due to 1 previous error
fn main() {
struct User {
    username: String,
    email: String,
    sign_in_count: u64
}

let user1 = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let user2 = user1;

println!("user1 = {}, {}", user1.username, user1.email);
println!("user2 = {}, {}", user2.username, user2.email);
}

Структури

Клониране на структури

За да можем да създаваме копия на нашата структура, тя трябва да имплементира trait-а Clone.
Чрез атрибута #[derive(Clone)] компилатора автоматично ще ни създаде имплементация на Clone.
Аналогично #[derive(Copy)] ще имплементира Copy - но трябва всички полета да са Copy.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#[derive(Clone)]
struct User {
    username: String,
    email: String,
    sign_in_count: u64
}

let user1 = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let user2 = user1.clone();

println!("user1 = {}, {}", user1.username, user1.email);
println!("user2 = {}, {}", user2.username, user2.email);
user1 = Иванчо, ivan40@abv.bg user2 = Иванчо, ivan40@abv.bg
fn main() {
#[derive(Clone)]
struct User {
    username: String,
    email: String,
    sign_in_count: u64
}

let user1 = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let user2 = user1.clone();

println!("user1 = {}, {}", user1.username, user1.email);
println!("user2 = {}, {}", user2.username, user2.email);
}

Структури

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

Аналогично можем да използваме атрибута #[derive(Debug)] за да получим имплементация на trait-а Debug.
Това ни позволява да принтираме нашата структура с println! инползвайки placeholder {:?}.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#[derive(Clone, Debug)]
struct User {
    username: String,
    email: String,
    sign_in_count: u64
}

let user1 = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let user2 = user1.clone();

println!("user1 = {:?}", user1);
println!("user2 = {:?}", user2);
user1 = User { username: "Иванчо", email: "ivan40@abv.bg", sign_in_count: 10 } user2 = User { username: "Иванчо", email: "ivan40@abv.bg", sign_in_count: 10 }
fn main() {
#[derive(Clone, Debug)]
struct User {
    username: String,
    email: String,
    sign_in_count: u64
}

let user1 = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let user2 = user1.clone();

println!("user1 = {:?}", user1);
println!("user2 = {:?}", user2);
}

Структури

Struct update синтаксис

Можем да дадем стойност само на част от полетата и останалите да попълним от друга инстанция

1 2 3 4 5 6 7 8 9 10 11 12
let user = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let hacker = User {
    email: String::from("hackerman@l33t.hax"),
    ..user
};

println!("{:?}", hacker);
User { username: "Иванчо", email: "hackerman@l33t.hax", sign_in_count: 10 }
#[derive(Debug)]
struct User { username: String, email: String, sign_in_count: u64 }
fn main() {
let user = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let hacker = User {
    email: String::from("hackerman@l33t.hax"),
    ..user
};

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

Структури

Struct update синтаксис

Това ще премести полетата от оригиналната инстанция

1 2 3 4 5 6 7 8 9 10 11 12 13
let user = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let hacker = User {
    email: String::from("hackerman@l33t.hax"),
    ..user
};

println!("{:?}", hacker);
println!("{:?}", user);
error[E0382]: borrow of partially moved value: `user` --> src/bin/main_99773612f004f2399763eb71a56006b2f8c4c270.rs:16:18 | 10 | let hacker = User { | ______________- 11 | | email: String::from("hackerman@l33t.hax"), 12 | | ..user 13 | | }; | |_- value partially moved here ... 16 | println!("{:?}", user); | ^^^^ value borrowed here after partial move | = note: partial move occurs because `user.username` 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) For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` (bin "main_99773612f004f2399763eb71a56006b2f8c4c270") due to 1 previous error
#[derive(Debug)]
struct User { username: String, email: String, sign_in_count: u64 }
fn main() {
let user = User {
    username: String::from("Иванчо"),
    email: String::from("ivan40@abv.bg"),
    sign_in_count: 10,
};

let hacker = User {
    email: String::from("hackerman@l33t.hax"),
    ..user
};

println!("{:?}", hacker);
println!("{:?}", user);
}

Структури

Struct update синтаксис

Синтаксиса е удобен за попълване на стойности по подразбиране.
Напр. ако структурата имплементира трейта Default можем да използваме функцията default.

1 2 3 4 5 6
let user = User {
    username: String::from("Иванчо"),
    ..User::default()
};

println!("{:?}", user);
User { username: "Иванчо", email: "", sign_in_count: 0 }
#[derive(Debug, Default)]
struct User { username: String, email: String, sign_in_count: u64 }
fn main() {
let user = User {
    username: String::from("Иванчо"),
    ..User::default()
};

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

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

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

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

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

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
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
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
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@abv.bg"));
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@abv.bg"));
}

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

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

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

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

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

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

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

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

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

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

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

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

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

Методи

1 2 3 4 5 6 7
struct Rectangle { width: f64, height: f64 }

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

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

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

Методи

1 2 3 4 5 6 7
struct Rectangle { width: f64, height: f64 }

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

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

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

Методи

1 2 3 4 5 6 7
struct Rectangle { width: f64, height: f64 }

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

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

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

Типа Self

1 2 3 4 5 6 7
struct Rectangle { width: f64, height: f64 }

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

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

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

Типа Self

1 2 3 4 5 6 7
struct Rectangle { width: f64, height: f64 }

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

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

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

Типа Self

1 2 3 4 5 6 7
struct Rectangle { width: f64, height: f64 }

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

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

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

Методи

1 2 3 4 5 6 7 8 9 10 11 12 13
impl Rectangle {
    fn area(&self) -> f64 {
        self.width * self.height
    }
    // е еквиваленто на
    fn area(self: &Self) -> f64 {
        self.width * self.height
    }
    // е еквиваленто на
    fn area(self: &Rectangle) -> f64 {
        self.width * self.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 = 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 = 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() {}

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

Newtype wrapper

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

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

fn main() {}

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

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

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

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

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

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

Защо?

Enums

Защо?

Enums

Защо?

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

// множеството от възможни стойности за `User` е декартовото произведение
// String × String × u64

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

Защо?

Enums

Защо?

Enums

Защо?

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
#[derive(Debug)]
#[repr(i32)]
enum Basic {
    A = 0,
    B = 12,
}

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

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

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

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

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

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

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

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

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

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: 24
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 стойности:

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

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 --> /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/option.rs:571:1 ::: /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/option.rs:575:5 | = note: 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` (bin "main_95c8682b7401bcccd982dc5ffc0ed7d72379cdae") due to 1 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"¯\_(ツ)_/¯"),
}
fn main() {
let x = 3;
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` (bin "main_48ccf2f6abbea81f52e3d53a72c573d98dd05a43") due to 1 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 7
let so_eighty = [8, 8, 8, 88, 8];
let mut iter8or = so_eighty.iter();

// `next()` метода на итератора връща `Option`
while let Some(8) = iter8or.next() {
    println!("∞");
}
∞ ∞ ∞
fn main() {
let so_eighty = [8, 8, 8, 88, 8];
let mut iter8or = so_eighty.iter();

// `next()` метода на итератора връща `Option`
while let Some(8) = iter8or.next() {
    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!("Нищо интересно"),
}
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

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!("Аз съм дърт."),
}
fn main() {
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` (bin "main_7fcc5d4a5bf3f85fa23c4492b0dcf73948710ca7") 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` (bin "main_0785486a8cc5ddcdb61694d420d4508a1c40d033") due to 1 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
users_map.iter().for_each(print_user_1);
users_map.iter().for_each(print_user_2);

fn print_user_1(pair: (&i32, &String)) {
    println!("{} => {}", pair.0, pair.1);
}

fn print_user_2((id, name): (&i32, &String)) {
    println!("{} => {}", id, name);
}
1 => Иванчо 5 => Петко 1 => Иванчо 5 => Петко
fn main() {
let mut users_map = std::collections::BTreeMap::new();
users_map.insert(1, "Иванчо".to_string());
users_map.insert(5, "Петко".to_string());
users_map.iter().for_each(print_user_1);
users_map.iter().for_each(print_user_2);

fn print_user_1(pair: (&i32, &String)) {
    println!("{} => {}", pair.0, pair.1);
}

fn print_user_2((id, name): (&i32, &String)) {
    println!("{} => {}", id, name);
}
}

Destructuring

На аргументи

1 2 3 4 5 6 7
users_map.iter().for_each(|pair| {
    println!("{} => {}", pair.0, pair.1)
});

users_map.iter().for_each(|(id, name)| {
    println!("{} => {}", id, name)
});
1 => Иванчо 5 => Петко 1 => Иванчо 5 => Петко
fn main() {
let mut users_map = std::collections::BTreeMap::new();
users_map.insert(1, "Иванчо".to_string());
users_map.insert(5, "Петко".to_string());
users_map.iter().for_each(|pair| {
    println!("{} => {}", pair.0, pair.1)
});

users_map.iter().for_each(|(id, name)| {
    println!("{} => {}", id, name)
});
}

Destructuring

На let bindings

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

1 2 3
let User { name: name_var, .. } = user;

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

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

Въпроси