02. Псевдоними, низове, композирани типове

02. Псевдоними, низове, композирани типове

02. Псевдоними, низове, композирани типове

11 октомври 2017

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

Въпроси

let x = 3;
let y = 5_i32;

x = x + y;

println!("{}", x);

Въпроси

let x = 3;
let y = 5_i32;

let x = x + y;

println!("{}", x);

Въпроси

let x = 3.14_f32 as u32;
let y = 5_i32;

let z = x + y;

println!("{}", z);

Въпроси

let x = 3.14_f32 as u32;
let y = 5_i32;

let z = (x as u8) + (y as u8);

println!("{}", z);

Въпроси

let x = 13;
let y =
    if (x > 42) {
        println("Бабо, много ти е голям хикса!");
        x
    } elsif x == 42 {
        println("Знам всичко!");
        x
    } else {
        x
    };

let x = loop { break { y } };

Въпроси

let x = 13;
let y = // Това е възможно
    if x > 42 { // Няма кръгли скоби, 'къдравите' скоби са задължителни!
        println!("Бабо, много ти е голям хикса!");
        x
    } else if x == 42 { // Няма elsif съкращения
        println!("Знам всичко!"); // Macro!
        x // Expression
    } else {
        x
    };

let x = loop { break { 5 } }; // както и това

Преговор

Основни типове

Кортежи

let x: (u32, bool) = (42, true);

println!("{}", x.0); // 42
println!("{}", x.1); // true

Основни типове

Кортежи

let (x, y) = (4, 5);

println!("{}", x); // 4
println!("{}", y); // 5

Tuple

Функция връщаща много стойности

fn multi(x: i32, y: i32) -> (i32, i32, i32) {
    (x * y, x + y, x - y)
}

let (a, b, c) = multi(4, 5);
let (d, e, _) = multi(4, 5); // Игнориране
let (_, f, _) = multi(4, 5); // Игнориране

let (a, b, c): (i32, i32, i32) = multi(4, 5);

Stack & Heap

Стек (Stack)

Stack & Heap

Стек (Stack)

Stack & Heap

Стек (Stack)

// Пример за променливи върху стека
fn main() {
    let a = 3;
    let b = 42;
}

Примерни адреси:

0x7ffee0bb6c48
0x7ffee0bb6c4c

Stack & Heap

Динамична памет (Heap)

Stack & Heap

Динамична памет (Heap)

Собственост и заемане

Собственост

Собственост и заемане

Собственост

Правила

Собственост и заемане

Собственост

{
    let a = 123;

    // ...
}

Низове

Литерали

let s = "hello";

Низове

String

let s = String::from("hello");

Низове

let mut second = String::from("Баба");
second.push_str(" и дядо");     // push_str() конкатенира литерал към String

println!("{}", second);

Низове

let mut first = "Баба";
// first.push_str(" и дядо");   // грешка при компилиране

Присвояване

let x = 5;
let y = x;                        // копие на стойността

println!("{}, {}", x, y);

let s1 = String::from("hello");
let s2 = s1;                      // ??

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

String

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

s2 = s1

Побитово копиране на стека → двойна деалокация

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

s2 = s1

Копие на стека и на динамичната памет, което може да доведе до сериозно забавяне

s2 = s1

Семантика на местене (Move semantics)

Вместо копиране, което е скъпо в някои случаи, Rust използва семантика на местене

let x = 5;
let y = x;                        // копие на стойността

let s1 = String::from("hello");
let s2 = s1;                      // s1 не може да се използва след този ред

println!("{}", s2);
// println!("{}", s1);            // грешка при компилиране

Семантика на местене (Move semantics)

Вместо копиране, което е скъпо в някои случаи, Rust използва семантика на местене

println!("{}", s2);
// println!("{}", s1);            // грешка при компилиране
error[E0382]: use of moved value: `s1`
--> src/main.rs:9:20
  |
6 |     let s2 = s1;
  |         -- value moved here
...
9 |     println!("{}", s1);
  |                    ^^ value used here after move
  |
  = note: move occurs because `s1` has type `std::string::String`,
    which does not implement the `Copy` trait

Низове

Clone

Ако все пак искаме да копираме String, може да го направим чрез метода clone()

let s1 = String::from("hello");
let s2 = s1.clone();

println!("{}, {}!", s1, s2);

Собственост

Функции

При подаването на аргументи към функция важат същите семантики

fn main() {
    let s = String::from("hello");  // Дефинираме s

    takes_ownership(s);             // Стойността на s се мести във функцията и
                                    // затова не е валидна след този ред.

} // Тук s излиза от scope, но s е преместен и не се случва нищо особено.

fn takes_ownership(some_string: String) {
    println!("{}", some_string);
} // some_string излиза от scope и се извиква `drop`, което освобождава паметта.

Собственост

Функции

При подаването на аргументи към функция важат същите семантики

fn main() {
    let x = 5;                      // Дефинираме x

    makes_copy(x);                  // Тук стойността на x би се преместила във функцията,
                                    // но i32 е Copy, затова може да използваме x в последствие.

} // Тук x излиза от scope.

fn makes_copy(some_integer: i32) {
    println!("{}", some_integer);
} // some_integer излиза от scope, но не се случва нищо особено.

Собственост

Функции

Връщане на стойност от функция също може да прехвърля собственост

fn main() {
    let s1 = gives_ownership();
    let s2 = String::from("hello");
    let s3 = takes_and_gives_back(s2);
}

fn gives_ownership() -> String {
    let some_string = String::from("hello");
    some_string       // Тук местим стойността към функцията която е извикала gives_ownership
}

fn takes_and_gives_back(a_string: String) -> String {
    a_string
}

Собственост

Функции

fn main() {
    let s1 = String::from("hello");
    let (s2, len) = calculate_length(s1);

    println!("The length of '{}' is {}.", s2, len);
}

fn calculate_length(s: String) -> (String, usize) {
    let length = s.len(); // len() връща дължината на String.
    (s, length)
}

Собственост и заемане

Заемане (borrowing)

А какво ако искаме да използваме стойност във функция без да я местим всеки път?

Собственост и заемане

Псевдоними

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

Псевдоними

Представяне

Псевдоними

Непроменим псевдоним (immutable reference)

fn main() {
    let s = String::from("hello");
    change(&s);
}

fn change(some_string: &String) {
    some_string.push_str(", world");
}
error: cannot borrow immutable borrowed content `*some_string` as mutable
--> error.rs:8:5
  |
8 |     some_string.push_str(", world");
  |     ^^^^^^^^^^^ 

Псевдоними

Променим псевдоним (mutable reference)

fn main() {
    let mut s = String::from("hello");
    change(&mut s);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

Псевдоними

Правила

1. По всяко време може да съществува само едно от следните:

2. Псевдонимите винаги са валидни

Псевдоними

Borrow checker

let mut s = String::from("hello");

let r1 = &mut s;
let r2 = &mut s;
error[E0499]: cannot borrow `s` as mutable more than once at a time
--> src/main.rs:5:19
  |
4 |     let r1 = &mut s;
  |                   - first mutable borrow occurs here
5 |     let r2 = &mut s;
  |                   ^ second mutable borrow occurs here
6 | }
  | - first borrow ends here 

Псевдоними

Borrow checker

let mut s = String::from("hello");

{
    let r1 = &mut s;
}

let r2 = &mut s;

Псевдоними

Валидност

let s1 = String::from("hello");
let r = &s1;

let s2 = s1;    // грешка

Псевдоними

Валидност

let r;
{
    let s = String::from("hello");
    r = &s;
}

println!("{}", r);

Псевдоними

Валидност

error[E0597]: `s` does not live long enough
--> src/main.rs:6:5
  |
5 |         r = &s;
  |              - borrow occurs here
6 |     }
  |     ^ `s` dropped here while still borrowed
...
9 | }
  | - borrowed value needs to live until here 

Псевдоними

let s = String::from("first");
let r = &s;

let s = String::from("second");

println!("{}", r);
println!("{}", s);

Псевдоними

let s = String::from("hello");
let s = &s;

println!("{}", s);

Въпроси