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

09 октомври 2018

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

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

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

Въпрос 1

Къде е грешката?

1 2 3 4 5 6
let x = 3;
let y = 5_i32;

x = x + y;

println!("{}", x);

Въпрос 1

Къде е грешката?

1 2 3 4 5 6
let x = 3;
let y = 5_i32;

x = x + y;

println!("{}", x);
error[E0384]: cannot assign twice to immutable variable `x`
 --> /src/main_0.rs:6:1
  |
3 | let x = 3;
  |     - first assignment to `x`
...
6 | x = x + y;
  | ^^^^^^^^^ cannot assign twice to immutable variable

Въпрос 1

Къде е грешката?

1 2 3 4 5 6
let x = 3;
let y = 5_i32;

let x = x + y;

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

Въпрос 2

Къде е грешката?

1 2 3 4 5 6
let x = 3.14_f32 as u32;
let y = 5_i32;

let z = x + y;

println!("{}", z);

Въпрос 2

Къде е грешката?

1 2 3 4 5 6
let x = 3.14_f32 as u32;
let y = 5_i32;

let z = x + y;

println!("{}", z);
error[E0308]: mismatched types
 --> /src/main_2.rs:6:13
  |
6 | let z = x + y;
  |             ^ expected u32, found i32

error[E0277]: cannot add `i32` to `u32`
 --> /src/main_2.rs:6:11
  |
6 | let z = x + y;
  |           ^ no implementation for `u32 + i32`
  |
  = help: the trait `std::ops::Add<i32>` is not implemented for `u32`

Въпрос 2

Къде е грешката?

1 2 3 4 5 6
let x = 3.14_f32 as u32;
let y = 5_i32;

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

println!("{}", z);
8

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Присвояване

1 2
let a = 7;
let b = a;

Присвояване

1 2 3 4
let a = 7;
let b = a;

println!("a = {}, b = {}", a, b);
a = 7, b = 7

Присвояване

1 2
let a = "Hello";
let b = a;

Присвояване

1 2 3 4 5
let a = "Hello";
let b = a;

println!("{}!", a);
println!("{} again!", b);
Hello!
Hello again!

Присвояване

1 2
let s1 = String::from("Cookies!");
let s2 = s1;

Присвояване

1 2 3 4 5
let s1 = String::from("Cookies!");
let s2 = s1;

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

Присвояване

1 2 3 4 5
let s1 = String::from("Cookies!");
let s2 = s1;

println!("{}", s1);
println!("Mmm, {}", s2);
error[E0382]: use of moved value: `s1`
 --> /src/main_9.rs:5:16
  |
3 | let s2 = s1;
  |     -- value moved here
4 | 
5 | println!("{}", s1);
  |                ^^ value used here after move
  |
  = note: move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait

Присвояване

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

String

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

s2 = s1

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

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

s2 = s1

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

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

s2 = s1

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

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

s2 = s1

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

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

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

1 2 3 4 5
let s1 = String::from("Cookies!");
let s2 = s1;

println!("{}", s1);
println!("Mmm, {}", s2);
error[E0382]: use of moved value: `s1`
 --> /src/main_9.rs:5:16
  |
3 | let s2 = s1;
  |     -- value moved here
4 | 
5 | 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()

Клониране

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

1 2 3 4 5
let s1 = String::from("Cookies!");
let s2 = s1.clone();

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

Низове

А защо това е проблем само при String, а не при литералите?

Низове

Литерали

1
let s = "hello";

  • Заделя се в статичната памет на програмата
  • Непроменим (immutable)

String

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

  • Заделя се в динамичната памет
  • Може да се променя (mutable)

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

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

Собственост

1 2 3 4 5
{
    let a = 123;

    // ...
}

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

Собственост

1 2 3 4 5
{
    let a = 123;

    // ...
}

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

Собственост

1 2 3 4 5
{
    let a = 123;

    // ...
}

Правила

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

Собственост

1 2 3 4 5
{
    let a = 123;

    // ...
}

Правила

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

Собственост

1 2 3 4 5
{
    let a = 123;

    // ...
}

Правила

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

Собственост

1 2 3 4 5
{
    let a = 123;

    // ...
}

Правила

Собственост

Функции

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

1 2 3 4 5 6 7 8 9 10 11
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 и се освобождава паметта.
hello

Собственост

Функции

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

1 2 3 4 5 6 7 8 9 10 11
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, но не се случва нищо особено.
5

Собственост

Функции

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

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

Собственост

Функции

1 2 3 4 5 6 7 8 9 10 11
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)
}
The length of 'hello' is 5.

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

Заемане (borrowing)

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

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

Псевдоними

1 2 3 4 5 6 7 8 9 10
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()
}
The length of 'hello' is 5.

Псевдоними

Представяне

Псевдоними

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

1 2 3 4 5 6 7 8 9
fn main() {
    let s = String::from("hello");
    change(&s);
    println!("{}", s);
}

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

Псевдоними

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

1 2 3 4 5 6 7 8 9
fn main() {
    let s = String::from("hello");
    change(&s);
    println!("{}", s);
}

fn change(some_string: &String) {
    some_string.push_str(", world");
}
error[E0596]: cannot borrow immutable borrowed content `*some_string` as mutable
 --> /src/main_16.rs:9:5
  |
8 | fn change(some_string: &String) {
  |                        ------- use `&mut String` here to make mutable
9 |     some_string.push_str(", world");
  |     ^^^^^^^^^^^ cannot borrow as mutable

Псевдоними

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

1 2 3 4 5 6 7 8 9
fn main() {
    let mut s = String::from("hello");
    change(&mut s);
    println!("{}", s);
}

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

Псевдоними

Правила

Псевдоними

Borrow checker

1 2 3 4
let mut s = String::from("hello");

let r1 = &mut s;
let r2 = &mut s;

Псевдоними

Borrow checker

1 2 3 4
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_18.rs:6:15
  |
5 | let r1 = &mut s;
  |               - first mutable borrow occurs here
6 | let r2 = &mut s;
  |               ^ second mutable borrow occurs here
7 | }
  | - first borrow ends here

Псевдоними

Borrow checker

1 2 3 4 5 6 7
let mut s = String::from("hello");

{
    let r1 = &mut s;
}

let r2 = &mut s;

Псевдоними

Валидност

1 2 3 4
let s1 = String::from("hello");
let r = &s1;

let s2 = s1;
error[E0505]: cannot move out of `s1` because it is borrowed
 --> /src/main_20.rs:6:5
  |
4 | let r = &s1;
  |          -- borrow of `s1` occurs here
5 | 
6 | let s2 = s1;
  |     ^^ move out of `s1` occurs here

Псевдоними

Валидност

1 2 3 4
let s1 = String::from("hello");
let r = &s1;

let s2 = s1;
error[E0505]: cannot move out of `s1` because it is borrowed
 --> /src/main_20.rs:6:5
  |
4 | let r = &s1;
  |          -- borrow of `s1` occurs here
5 | 
6 | let s2 = s1;
  |     ^^ move out of `s1` occurs here

Псевдоними

Валидност

1 2 3 4
let s1 = String::from("hello");
let r = &s1;

let s2 = s1;
error[E0505]: cannot move out of `s1` because it is borrowed
 --> /src/main_20.rs:6:5
  |
4 | let r = &s1;
  |          -- borrow of `s1` occurs here
5 | 
6 | let s2 = s1;
  |     ^^ move out of `s1` occurs here

Псевдоними

Валидност

1 2 3 4 5 6 7
let r;
{
    let s = String::from("hello");
    r = &s;
}

println!("{}", r);

Псевдоними

Валидност

1 2 3 4 5 6 7
let r;
{
    let s = String::from("hello");
    r = &s;
}

println!("{}", r);
error[E0597]: `s` does not live long enough
  --> /src/main_21.rs:6:10
   |
6  |     r = &s;
   |          ^ borrowed value does not live long enough
7  | }
   | - `s` dropped here while still borrowed
...
10 | }
   | - borrowed value needs to live until here

Псевдоними

Валидност

1 2 3 4 5 6 7
let r;
{
    let s = String::from("hello");
    r = &s;
}

println!("{}", r);
error[E0597]: `s` does not live long enough
  --> /src/main_21.rs:6:10
   |
6  |     r = &s;
   |          ^ borrowed value does not live long enough
7  | }
   | - `s` dropped here while still borrowed
...
10 | }
   | - borrowed value needs to live until here

Псевдонимът не може да надживее обекта, към който сочи

Псевдоними

1 2 3 4 5 6 7
let s = String::from("first");
let r = &s;

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

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

Псевдоними

1 2 3 4 5 6 7
let s = String::from("first");
let r = &s;

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

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

Псевдоними

1 2 3 4
let s = String::from("hello");
let s = &s;

println!("{}", s);

Псевдоними

1 2 3 4
let s = String::from("hello");
let s = &s;

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

Въпроси