Присвояване, копиране, референции

15 октомври 2019

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

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

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

Въпрос 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/bin/main_793bd1e82f6a5e8e900d20244b579b139e851656.rs:6:1 | 3 | let x = 3; | - | | | first assignment to `x` | help: make this binding mutable: `mut x` ... 6 | x = x + y; | ^^^^^^^^^ cannot assign twice to immutable variable
fn main() {
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;

let x = x + y;

println!("{}", x);
8
fn main() {
let x = 3;
let y = 5_i32;

let x = x + y;

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

Въпрос 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/bin/main_2e0ed2c7322a9afaac10ab153c9b25e128a54dd9.rs:6:13 | 6 | let z = x + y; | ^ expected u32, found i32 error[E0277]: cannot add `i32` to `u32` --> src/bin/main_2e0ed2c7322a9afaac10ab153c9b25e128a54dd9.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`
fn main() {
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 as u8) + (y as u8);

println!("{}", z);
8
fn main() {
let x = 3.14_f32 as u32;
let y = 5_i32;

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

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

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Присвояване

1 2
let a = 7;
let b = a;
fn main() {
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
fn main() {
let a = 7;
let b = a;

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

Присвояване

1 2
let a = "Hello";
let b = a;
fn main() {
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!
fn main() {
let a = "Hello";
let b = a;

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

Присвояване

1 2
let s1 = String::from("Cookies!");
let s2 = s1;
fn main() {
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]: borrow of moved value: `s1` --> src/bin/main_9bd3356d7798f6992589bc25a22e3d30f92002bb.rs:5:16 | 2 | let s1 = String::from("Cookies!"); | -- move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait 3 | let s2 = s1; | -- value moved here 4 | 5 | println!("{}", s1); | ^^ value borrowed here after move
fn main() {
let s1 = String::from("Cookies!");
let s2 = s1;

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

Присвояване

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

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]: borrow of moved value: `s1` --> src/bin/main_9bd3356d7798f6992589bc25a22e3d30f92002bb.rs:5:16 | 2 | let s1 = String::from("Cookies!"); | -- move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait 3 | let s2 = s1; | -- value moved here 4 | 5 | println!("{}", s1); | ^^ value borrowed here after move
fn main() {
let s1 = String::from("Cookies!");
let s2 = s1;

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

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

Клониране и копиране

trait Clone

Клониране и копиране

trait Clone

Клониране и копиране

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!
fn main() {
let s1 = String::from("Cookies!");
let s2 = s1.clone();

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

Клониране и копиране

trait Copy

Клониране и копиране

trait Copy

Клониране и копиране

trait Copy

Клониране и копиране

trait Copy

Клониране и копиране

trait Copy

Копиране

Числените типове имплементират Copy

1 2 3 4 5 6
let n1 = 0xbeef;
let n2 = n1;         // копира s2
let n3 = n1.clone(); // еквиваленто на `n3 = n1`

println!("{}", n2);
println!("Mmm, {:#x}", n3);
48879 Mmm, 0xbeef
fn main() {
let n1 = 0xbeef;
let n2 = n1;         // копира s2
let n3 = n1.clone(); // еквиваленто на `n3 = n1`

println!("{}", n2);
println!("Mmm, {:#x}", n3);
}

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

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

Собственост

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
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 и се освобождава паметта.

Собственост

Функции

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14
fn main() {
    let x = 5;     // Дефинираме x

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

    println!("This was a triumph");
    println!("x is still alive");
    println!("with the value of {}", x);
} // Тук x излиза от scope.

fn makes_copy(some_integer: i32) {
    println!("{}", some_integer);
} // some_integer излиза от scope, но не се случва нищо особено.
5 This was a triumph x is still alive with the value of 5
fn main() {
    let x = 5;     // Дефинираме x

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

    println!("This was a triumph");
    println!("x is still alive");
    println!("with the value of {}", x);
} // Тук x излиза от scope.

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

Собственост

Функции

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

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

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

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

Референции

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

Референции

Immutable

Референции

Immutable

Референции

Представяне

Референции

Immutable

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

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 `*some_string` as mutable, as it is behind a `&` reference --> src/bin/main_7a8d06574d6b81de9d7bcefd13a155afc2a3b55a.rs:8:5 | 7 | fn change(some_string: &String) { | ------- help: consider changing this to be a mutable reference: `&mut std::string::String` 8 | some_string.push_str(", world"); | ^^^^^^^^^^^ `some_string` is a `&` reference, so the data it refers to cannot be borrowed as mutable
fn main() {
    let s = String::from("hello");
    change(&s);
    println!("{}", s);
}

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

Референции

Мutable

Референции

Мutable

Референции

Мutable

Референции

Мutable

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
fn main() {
    let mut s = String::from("hello");
    change(&mut s);
    println!("{}", s);
}

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

Референции

Правила

Референции

Правила

Референции

Валидност

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/bin/main_57ddabce60a0b2fc70095675e3a4176d6ec3e3dc.rs:5:5 | 5 | r = &s; | ^^^^^^ borrowed value does not live long enough 6 | } | - `s` dropped here while still borrowed 7 | 8 | println!("{}", r); | - borrow later used here
fn main() {
let r;
{
    let s = String::from("hello");
    r = &s;
}

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

Референции

Правила

Референции

Правила

Референции

Правила

Референции

Правила

Референции

Правила

Borrow checker

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

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

println!("{}, {}", r1, r2);

Borrow checker

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

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

println!("{}, {}", r1, r2);
error[E0499]: cannot borrow `s` as mutable more than once at a time --> src/bin/main_5bdec4f559fb3cb8b422d5856bd844f38ad67a0f.rs:5:10 | 4 | let r1 = &mut s; | ------ first mutable borrow occurs here 5 | let r2 = &mut s; | ^^^^^^ second mutable borrow occurs here 6 | 7 | println!("{}, {}", r1, r2); | -- first borrow later used here
fn main() {
let mut s = String::from("hello");

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

println!("{}, {}", r1, r2);
}

Borrow checker

Решение: не ги използвайте заедно

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

let r1 = &mut s;
println!("{}", r1);

let r2 = &mut s;
println!("{}", r2);
hello hello
#![allow(unused_variables)]
fn main() {
let mut s = String::from("hello");

let r1 = &mut s;
println!("{}", r1);

let r2 = &mut s;
println!("{}", r2);
}

Borrow checker

За повече яснота за живота на r1:

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

{
    let r1 = &mut s;
    println!("{}", r1);
}

let r2 = &mut s;
println!("{}", r2);
hello hello
fn main() {
let mut s = String::from("hello");

{
    let r1 = &mut s;
    println!("{}", r1);
}

let r2 = &mut s;
println!("{}", r2);
}

Borrow checker

Не можем да преместим стойност докато има референция към нея

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

let s2 = s1;
println!("{}", r);
error[E0505]: cannot move out of `s1` because it is borrowed --> src/bin/main_81fbc5758c4c34a72422dd0521641f6895111026.rs:5:10 | 3 | let r = &s1; | --- borrow of `s1` occurs here 4 | 5 | let s2 = s1; | ^^ move out of `s1` occurs here 6 | println!("{}", r); | - borrow later used here
fn main() {
let s1 = String::from("hello");
let r = &s1;

let s2 = s1;
println!("{}", r);
}

Референции

Към скрита (shadowed) променлива

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

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

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

Референции

Към скрита (shadowed) променлива

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
fn main() {
let s = String::from("first");
let r = &s;

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

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

Референции

Към скрита (shadowed) променлива

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

println!("{}", s);

Референции

Към скрита (shadowed) променлива

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

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

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

Референции

Към временна стойност

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

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

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

Референции

Към временна стойност

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

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

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

Референции

mutable → immutable

1 2 3 4 5 6 7 8 9 10
fn main() {
    let mut s = String::from("hello");
    let r = &mut s;

    greet_cookies(r);
}

fn greet_cookies(greeting: &String) {
    println!("{}, cookies", greeting);
}
fn main() {
    let mut s = String::from("hello");
    let r = &mut s;

    greet_cookies(r);
}

fn greet_cookies(greeting: &String) {
    println!("{}, cookies", greeting);
}

Референции

mutable → immutable

1 2 3 4 5 6 7 8 9 10
fn main() {
    let mut s = String::from("hello");
    let r = &mut s;

    greet_cookies(r);
}

fn greet_cookies(greeting: &String) {
    println!("{}, cookies", greeting);
}
hello, cookies
fn main() {
    let mut s = String::from("hello");
    let r = &mut s;

    greet_cookies(r);
}

fn greet_cookies(greeting: &String) {
    println!("{}, cookies", greeting);
}

Референции

mutable → mutable

1 2 3 4 5 6 7 8 9 10 11
fn main() {
    let mut s = String::from("mmm");
    let r = &mut s;

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

fn get_cookies(s: &mut String) {
    s.push_str(", cookies");
}
fn main() {
    let mut s = String::from("mmm");
    let r = &mut s;

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

fn get_cookies(s: &mut String) {
    s.push_str(", cookies");
}

Референции

mutable → mutable

1 2 3 4 5 6 7 8 9 10 11
fn main() {
    let mut s = String::from("mmm");
    let r = &mut s;

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

fn get_cookies(s: &mut String) {
    s.push_str(", cookies");
}
mmm, cookies
fn main() {
    let mut s = String::from("mmm");
    let r = &mut s;

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

fn get_cookies(s: &mut String) {
    s.push_str(", cookies");
}

Низове

Литерали

1
let s: &str = "hello";
fn main() {
let s: &str = "hello";
}

Низове

Литерали

1
let s: &str = "hello";
fn main() {
let s: &str = "hello";
}

Низове

Литерали

1
let s: &str = "hello";
fn main() {
let s: &str = "hello";
}

Низове

Литерали

1
let s: &str = "hello";
fn main() {
let s: &str = "hello";
}

Низове

Литерали

1
let s: &str = "hello";
fn main() {
let s: &str = "hello";
}

Низове

Литерали

1
let s: &str = "hello";
fn main() {
let s: &str = "hello";
}

Низове

String

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

Низове

String

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

Низове

String

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

Низове

String

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

Низове

Резени

Можем да вземем част от низ

1 2 3 4 5
let s = String::from("hello, world");
let r1 = &s[..];
let r2 = &r1[1..4];

println!("{}", r2);
ell
#![allow(unused_variables)]
fn main() {
let s = String::from("hello, world");
let r1 = &s[..];
let r2 = &r1[1..4];

println!("{}", r2);
}

Низове

Резени

Низове

Резени

Низове

Резени

Низове

Резени

Типа &str

Типа &str

Типа &str

Типа &str

Типа &mut str

Типа &mut str

Типа &mut str

Типа &mut str

Вектори

Tипа Vec

1 2 3 4 5 6
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);

println!("{:?}", v);
[1, 2, 3]
#![allow(unused_variables)]
fn main() {
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);

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

Вектори

Tипа Vec

1 2 3 4 5 6
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);

println!("{:?}", v);
[1, 2, 3]
#![allow(unused_variables)]
fn main() {
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);

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

Вектори

Tипа Vec

1 2 3 4 5 6
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);

println!("{:?}", v);
[1, 2, 3]
#![allow(unused_variables)]
fn main() {
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);

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

Вектори

макрото vec!

1 2 3
let v = vec![1, 2, 3];

println!("{:?}", v);
[1, 2, 3]
#![allow(unused_variables)]
fn main() {
let v = vec![1, 2, 3];

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

Типа &[T]

Типа &[T]

Типа &[T]

Типа &[T]

&[T]

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

1 2 3 4
let arr = [1, 2, 3];
let slice = &arr[..];

println!("{:?}", slice);
[1, 2, 3]
#![allow(unused_variables)]
fn main() {
let arr = [1, 2, 3];
let slice = &arr[..];

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

&[T]

Резен от масив литерал

1 2 3
let slice = &[1, 2, 3];

println!("{:?}", slice);
[1, 2, 3]
#![allow(unused_variables)]
fn main() {
let slice = &[1, 2, 3];

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

&[T]

Резен от вектор

1 2 3 4
let v = vec![1, 2, 3];
let slice = &v[..];

println!("{:?}", slice);
[1, 2, 3]
#![allow(unused_variables)]
fn main() {
let v = vec![1, 2, 3];
let slice = &v[..];

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

Въпроси