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

10 октомври 2024

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

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

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

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Низове

Низове литерали

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
let a: &'static str = "Hello";
fn main() {
let a: &'static str = "Hello";
}

Низове

Низове литерали

1
let a: &'static str = "Hello";
fn main() {
let a: &'static str = "Hello";
}

Низове

Низове литерали

1
let a: &'static str = "Hello";
fn main() {
let a: &'static str = "Hello";
}

Низове

Низове литерали

1 2 3
let a = "Hello";
let b = " again!";
let message = a + b;
error[E0369]: cannot add `&str` to `&str` --> src/bin/main_ff85fd0fe5cb754d5812d4e753254866d53e2a47.rs:4:17 | 4 | let message = a + b; | - ^ - &str | | | | | `+` cannot be used to concatenate two `&str` strings | &str | = note: string concatenation requires an owned `String` on the left help: create an owned `String` from a string reference | 4 | let message = a.to_owned() + b; | +++++++++++ For more information about this error, try `rustc --explain E0369`. error: could not compile `rust` (bin "main_ff85fd0fe5cb754d5812d4e753254866d53e2a47") due to 1 previous error
fn main() {
let a = "Hello";
let b = " again!";
let message = a + b;
}

Низове

Динамични низове

1 2 3 4 5
let mut a = String::from("Hello");
println!("{}!", a);

a.push_str(" again!");
println!("{}", a);
Hello! Hello again!
fn main() {
let mut a = String::from("Hello");
println!("{}!", a);

a.push_str(" again!");
println!("{}", a);
}

Низове

Динамични низове

1
let a: String = String::from("Hello");
fn main() {
let a: String = String::from("Hello");
}

Низове

Динамични низове

1
let a: String = String::from("Hello");
fn main() {
let a: String = String::from("Hello");
}

Низове

Динамични низове

1
let a: String = String::from("Hello");
fn main() {
let a: String = String::from("Hello");
}

Низове

Динамични низове

Следните начини за създаване на динамичен низ са напълно еквивалентни

1 2 3
let s1 = String::from("Hello");
let s2 = "Hello".to_string();
let s3 = "Hello".to_owned();
fn main() {
let s1 = String::from("Hello");
let s2 = "Hello".to_string();
let s3 = "Hello".to_owned();
}

Присвояване

Присвояване

Статични низове

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

println!("{}!", a);
println!("{} again!", b);
fn main() {
let a = "Hello";
let b = a;

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

Присвояване

Статични низове

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 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 `String`, which does not implement the `Copy` trait 3 | let s2 = s1; | -- value moved here 4 | 5 | println!("{}", s1); | ^^ value borrowed here after move | = 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) help: consider cloning the value if the performance cost is acceptable | 3 | let s2 = s1.clone(); | ++++++++ For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` (bin "main_9bd3356d7798f6992589bc25a22e3d30f92002bb") due to 1 previous error
fn main() {
let s1 = String::from("Cookies!");
let s2 = s1;

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

Присвояване

Ownership

Собственост

Собственост

В някои други езици (с менaжирана памет)

1 2 3 4
Foo myFoo = new Foo();

myObj1.foo = myFoo;
myObj2.foo = myFoo;

Собственост

В Rust (и други езици)

1 2 3 4 5 6
let my_foo = Foo::new();

{
    let foo_ref = &my_foo;
    // do work with `foo_ref`
}
struct Foo {}
impl Foo { fn new() -> Self { Foo{} } }
fn main() {
let my_foo = Foo::new();

{
    let foo_ref = &my_foo;
    // do work with `foo_ref`
}
}

Собственост

В Rust (и други езици)

1 2 3 4 5 6
let my_foo = Foo::new();

{
    let foo_ref = &my_foo;
    // do work with `foo_ref`
}
struct Foo {}
impl Foo { fn new() -> Self { Foo{} } }
fn main() {
let my_foo = Foo::new();

{
    let foo_ref = &my_foo;
    // do work with `foo_ref`
}
}

Собственост

Lifetime

1 2 3 4 5 6
fn some_func() {
    let foo1 = Foo::new();
    let foo2 = Foo::new();

} // извиква се деструктора на `foo2`,
  // после и на `foo1`
struct Foo {}
impl Foo { fn new() -> Self { Foo{} } }
fn main() {}
fn some_func() {
    let foo1 = Foo::new();
    let foo2 = Foo::new();

} // извиква се деструктора на `foo2`,
  // после и на `foo1`

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

При присвояване се прехвърля собствеността над стойността

1 2 3 4 5 6 7
let s1 = String::from("Cookies!");
// `s1` е собственик на стойността "низа Cookies!"

let s2 = s1;
// `s2` е собственик на стойността "низа Cookies!"

println!("Mmm, {}", s2);
Mmm, Cookies!
fn main() {
let s1 = String::from("Cookies!");
// `s1` е собственик на стойността "низа Cookies!"

let s2 = s1;
// `s2` е собственик на стойността "низа Cookies!"

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

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

При присвояване се прехвърля собствеността над стойността

1 2 3 4 5 6 7
let s1 = String::from("Cookies!");
// `s1` е собственик на стойността "низа Cookies!"

let s2 = s1;
// `s2` е собственик на стойността "низа Cookies!"

println!("Mmm, {}", s2);
Mmm, Cookies!
fn main() {
let s1 = String::from("Cookies!");
// `s1` е собственик на стойността "низа Cookies!"

let s2 = s1;
// `s2` е собственик на стойността "низа Cookies!"

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

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

При присвояване се прехвърля собствеността над стойността

1 2 3 4 5 6 7
let s1 = String::from("Cookies!");
// `s1` е собственик на стойността "низа Cookies!"

let s2 = s1;
// `s2` е собственик на стойността "низа Cookies!"

println!("Mmm, {}", s2);
Mmm, Cookies!
fn main() {
let s1 = String::from("Cookies!");
// `s1` е собственик на стойността "низа Cookies!"

let s2 = s1;
// `s2` е собственик на стойността "низа Cookies!"

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

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

При присвояване се прехвърля собствеността над стойността

1 2 3 4 5 6 7
let s1 = String::from("Cookies!");
// `s1` е собственик на стойността "низа Cookies!"

let s2 = s1;
// `s2` е собственик на стойността "низа Cookies!"

println!("Mmm, {}", s2);
Mmm, Cookies!
fn main() {
let s1 = String::from("Cookies!");
// `s1` е собственик на стойността "низа Cookies!"

let s2 = s1;
// `s2` е собственик на стойността "низа Cookies!"

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

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

След преместване старата променлива не може да се използва.

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 `String`, which does not implement the `Copy` trait 3 | let s2 = s1; | -- value moved here 4 | 5 | println!("{}", s1); | ^^ value borrowed here after move | = 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) help: consider cloning the value if the performance cost is acceptable | 3 | let s2 = s1.clone(); | ++++++++ For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` (bin "main_9bd3356d7798f6992589bc25a22e3d30f92002bb") due to 1 previous error
fn main() {
let s1 = String::from("Cookies!");
let s2 = s1;

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

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

Ако искаме да ползваме и двете променливи, трябва да направим копие на стойността

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

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

При преместване:

Примери

Функции с подаване на String

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

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
fn main() {
    let s1 = gives_ownership();
    let s2 = takes_and_gives_back(s1);
}

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

fn takes_and_gives_back(a_string: String) -> String {
    a_string
}
fn main() {
    let s1 = gives_ownership();
    let s2 = takes_and_gives_back(s1);
}

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

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();
    (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();
    (s, length)
}

Референции

Референции

Референции

Референции

Референции

Референции

Референции

Примери

Заемане на стойност (borrowing)

1 2 3 4 5 6 7 8 9 10
fn main() {
    let x = 123;

    {
        let ref_x = &x;
        println!("x = {}", ref_x);
    }

    println!("x = {}", x);
}
x = 123 x = 123
fn main() {
    let x = 123;

    {
        let ref_x = &x;
        println!("x = {}", ref_x);
    }

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

Примери

Валидност

1 2 3 4 5 6 7 8 9 10
fn main() {
    let r;

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

    println!("{}", r);
}
error[E0597]: `s` does not live long enough --> src/bin/main_71adf588d2710ea65d8d814495506ae9ee825001.rs:6:13 | 5 | let s = String::from("hello"); | - binding `s` declared here 6 | r = &s; | ^^ borrowed value does not live long enough 7 | } | - `s` dropped here while still borrowed 8 | 9 | println!("{}", r); | - borrow later used here For more information about this error, try `rustc --explain E0597`. error: could not compile `rust` (bin "main_71adf588d2710ea65d8d814495506ae9ee825001") due to 1 previous error
fn main() {
    let r;

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

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

Примери

Валидност

1 2 3 4
fn returns_string() -> &String {
    let s = String::from("hello");
    &s
}
error[E0106]: missing lifetime specifier --> src/bin/main_5cb43ac4011a50cf250ff0feb51cfdfd0cadb93a.rs:2:24 | 2 | fn returns_string() -> &String { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` | 2 | fn returns_string() -> &'static String { | +++++++ help: instead, you are more likely to want to return an owned value | 2 - fn returns_string() -> &String { 2 + fn returns_string() -> String { | error[E0515]: cannot return reference to local variable `s` --> src/bin/main_5cb43ac4011a50cf250ff0feb51cfdfd0cadb93a.rs:4:5 | 4 | &s | ^^ returns a reference to data owned by the current function Some errors have detailed explanations: E0106, E0515. For more information about an error, try `rustc --explain E0106`. error: could not compile `rust` (bin "main_5cb43ac4011a50cf250ff0feb51cfdfd0cadb93a") due to 2 previous errors
fn main() {}
fn returns_string() -> &String {
    let s = String::from("hello");
    &s
}

Примери

Подаване на функция

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

Примери

Мутиране през функция

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
fn main() {
    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_c6f2dc9cfd0028307ee888b509415f2aa84fc40e.rs:5:14 | 2 | let s1 = String::from("hello"); | -- binding `s1` declared here 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 | help: consider cloning the value if the performance cost is acceptable | 3 - let r = &s1; 3 + let r = s1.clone(); | For more information about this error, try `rustc --explain E0505`. error: could not compile `rust` (bin "main_c6f2dc9cfd0028307ee888b509415f2aa84fc40e") due to 1 previous error
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);
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);
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 4
let s = &mut String::from("hello");
s.push_str(", world");

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

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

Borrow checker

Borrow checker

Правило

Borrow checker

Правило

Borrow checker

Правило

Borrow checker

Защо?

Borrow checker

Защо?

Borrow checker

Защо?

Borrow checker

Защо?

Borrow checker

Защо?

Borrow checker

Защо?

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 For more information about this error, try `rustc --explain E0499`. error: could not compile `rust` (bin "main_5bdec4f559fb3cb8b422d5856bd844f38ad67a0f") due to 1 previous error
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
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

За повече яснота за живота на 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

Класически пример от c++ - инвалидация на итератори

1 2 3 4 5 6 7 8 9
let mut vec = vec![1, 2, 3];

for val in vec.iter() {
    do_something(val);

    if some_condition {
        vec.push(99);
    }
}
error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable --> src/bin/main_9036c0a5609ad39a3ebd2868f8e68cf6133e5a72.rs:10:9 | 6 | for val in vec.iter() { | ---------- | | | immutable borrow occurs here | immutable borrow later used here ... 10 | vec.push(99); | ^^^^^^^^^^^^ mutable borrow occurs here For more information about this error, try `rustc --explain E0502`. error: could not compile `rust` (bin "main_9036c0a5609ad39a3ebd2868f8e68cf6133e5a72") due to 1 previous error
fn main() {
fn do_something(_: &i32) {}
let some_condition = false;
let mut vec = vec![1, 2, 3];

for val in vec.iter() {
    do_something(val);

    if some_condition {
        vec.push(99);
    }
}
}

Низове и резени

Низове и резени

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

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

let r1 = &s[1..4];
println!("{}", r1);

let r2 = &s[..s.len()-2]; // &s[..-2] не е възможно
println!("{}", r2);

let r3 = &s[..];
println!("{}", r3);
ell hello, wor hello, world
fn main() {
let s = String::from("hello, world");

let r1 = &s[1..4];
println!("{}", r1);

let r2 = &s[..s.len()-2]; // &s[..-2] не е възможно
println!("{}", r2);

let r3 = &s[..];
println!("{}", r3);
}

Низове и резени

Интервали

Низове и резени

Интервали

Низове и резени

Интервали

Низове и резени

Интервали

Низове и резени

Интервали

Низове и резени

Интервали

Низове и резени

Интервали

Низове и резени

Интервали

Низове и резени

Интервали

Низове и резени

Интервали

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

String

1
let my_name = String::from("Pascal Precht");
fn main() {
let my_name = String::from("Pascal Precht");
}



            [––––– my_name: String ––––]
            +––––––––+––––––––+––––––––+
stack frame │ ptr=•  │ cap=16 │ len=13 │
            +–––––│––+––––––––+––––––––+
              +–––+
              │
              │
            [–│–––––––––––––––––– ptr + len ––––––––––––––––––––]
            [-│------------------ ptr + cap --------------------------------]
            +–V–+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+
       heap │ P │ a │ s │ c │ a │ l │ ␣ │ P │ r │ e │ c │ h │ t │   │   │   │
            +–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+

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

&String

1 2
let my_name = String::from("Pascal Precht");
let r = &my_name;
fn main() {
let my_name = String::from("Pascal Precht");
let r = &my_name;
}
              +–––––––––––––––––––––––––––––––––––+
              │                                   │
            [–│––– my_name: String ––––]  [ r: &String ]
            +–V––––––+––––––––+––––––––+  +–––––––│––––+
stack frame │ ptr=•  │ cap=16 │ len=13 │  │   ptr=•    │
            +–––––│––+––––––––+––––––––+  +––––––––––––+
              +–––+
              │
              │
            [–│–––––––––––––––––– ptr + len ––––––––––––––––––––]
            [-│------------------ ptr + cap --------------------------------]
            +–V–+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+
       heap │ P │ a │ s │ c │ a │ l │ ␣ │ P │ r │ e │ c │ h │ t │   │   │   │
            +–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+

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

&str

1 2
let my_name = String::from("Pascal Precht");
let last_name = &my_name[7..];
fn main() {
let my_name = String::from("Pascal Precht");
let last_name = &my_name[7..];
}


            [––––– my_name: String ––––]  [last_name: &str]
            +––––––––+––––––––+––––––––+  +–––––––+–––––––+
stack frame │ ptr=•  │ cap=16 │ len=13 │  │ ptr=• │ len=6 │
            +–––––│––+––––––––+––––––––+  +–––––│–+–––––––+
              +–––+                             │
              │                           +–––––+
              │                           │
              │                           │
              │                         [–│––––––– str –––––––––]
            +–V–+–––+–––+–––+–––+–––+–––+–V–+–––+–––+–––+–––+–––+–––+–––+–––+
       heap │ P │ a │ s │ c │ a │ l │ ␣ │ P │ r │ e │ c │ h │ t │   │   │   │
            +–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+

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

&str

1 2
let my_name = "Pascal Precht";
let last_name = &my_name[7..];
fn main() {
let my_name = "Pascal Precht";
let last_name = &my_name[7..];
}


            [– my_name: &str –]           [last_name: &str]
            +––––––––+––––––––+           +–––––––+–––––––+
stack frame │ ptr=•  │ len=13 │           │ ptr=• │ len=6 │
            +–––––│––+––––––––+           +–––––│–+–––––––+
              +–––+                             │
              │                           +–––––+
              │                           │
              │                           │
              │                         [–│––––––– str –––––––––]
            +–V–+–––+–––+–––+–––+–––+–––+–V–+–––+–––+–––+–––+–––+
    .rodata │ P │ a │ s │ c │ a │ l │ ␣ │ P │ r │ e │ c │ h │ t │
            +–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+

Масиви и резени

Масиви и резени

Типа [T;N]

1 2
let point_coords = [1.0, 3.5, 0.0];  // тип [f32; 3]
println!("{:?}", point_coords);
[1.0, 3.5, 0.0]
fn main() {
let point_coords = [1.0, 3.5, 0.0];  // тип [f32; 3]
println!("{:?}", point_coords);
}

Масиви и резени

Типа [T;N]

1 2
let zero = [0.0; 3];    // тип [f32; 3]
println!("{:?}", zero);
[0.0, 0.0, 0.0]
fn main() {
let zero = [0.0; 3];    // тип [f32; 3]
println!("{:?}", zero);
}

Вектори

Tипа Vec<T>

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]
fn main() {
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);

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

Вектори

Типа Vec<T>

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

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

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

Вектори

Типа Vec<T>

1 2 3
let v = vec![0; 8];

println!("{:?}", v);
[0, 0, 0, 0, 0, 0, 0, 0]
fn main() {
let v = vec![0; 8];

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

Резени

1 2 3 4 5 6 7
let arr = [2, 4, 6, 8, 10];
let arr_slice = &arr[1..4];     // тип &[i32]
println!("{:?}", arr_slice);

let v = vec![2, 4, 6, 8, 10];
let vec_slice = &v[1..4];       // тип &[i32]
println!("{:?}", vec_slice);
[4, 6, 8] [4, 6, 8]
fn main() {
let arr = [2, 4, 6, 8, 10];
let arr_slice = &arr[1..4];     // тип &[i32]
println!("{:?}", arr_slice);

let v = vec![2, 4, 6, 8, 10];
let vec_slice = &v[1..4];       // тип &[i32]
println!("{:?}", vec_slice);
}

Резени

Типа &[T]

Резени

Типа &[T]

Резени

Типа &[T]

Резени

Типа &[T]

Резени

Литерали

1 2 3
let slice = &[2, 4, 6, 8, 10];

println!("{:?}", slice);
[2, 4, 6, 8, 10]
fn main() {
let slice = &[2, 4, 6, 8, 10];

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

Резени

Мутация

1 2 3 4 5 6 7 8 9
let mut v = vec![2, 4, 6, 8, 10, 12];
let slice = &mut v[1..4];   // тип &mut [i32]

for elem in slice.iter_mut() {
    *elem += 1;
}

println!("{:?}", slice);
println!("{:?}", v);
[5, 7, 9] [2, 5, 7, 9, 10, 12]
fn main() {
let mut v = vec![2, 4, 6, 8, 10, 12];
let slice = &mut v[1..4];   // тип &mut [i32]

for elem in slice.iter_mut() {
    *elem += 1;
}

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

Резени

Типа &mut [T]

Резени

Типа &mut [T]

Резени

Типа &mut [T]

Резени

Типа &mut [T]

Резени

Типа &mut [T]

Обобщение

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

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

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

1 2 3 4 5
let s1 = "Cookies!";
let s2 = s1;

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

Cookies! Mmm, Cookies!

fn main() {
let s1 = "Cookies!";
let s2 = s1;

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

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

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

Mmm, Cookies!

fn main() {
let s1 = String::from("Cookies!");
let s2 = s1;

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

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

1 2 3 4 5
let s1 = "Cookies!";
let s2 = s1;

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

Cookies! Mmm, Cookies!

fn main() {
let s1 = "Cookies!";
let s2 = s1;

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

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

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

Mmm, Cookies!

fn main() {
let s1 = String::from("Cookies!");
let s2 = s1;

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

Клониране

trait Clone

Клониране

trait Clone

1 2
// сигнатурата за `String`
fn clone(s: &String) -> String;

Клониране

trait Clone

1 2
// сигнатурата за `String`
fn clone(s: &String) -> String;

Клониране

Вече го видяхме в израза s1.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

За типове, които са Copy, не се използва семантика на местенето

Копиране

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

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

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

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

Копиране

Споделените референции (&T, &[T], &str) имплементират Copy

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

println!("{}", s1);
println!("Mmm, {}", s2);
Cookies! Mmm, Cookies!
fn main() {
let cookies = String::from("Cookies!");
let s1: &str = &cookies;
let s2: &str = s1;

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

Копиране

Споделените референции (&T, &[T], &str) имплементират Copy

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

println!("{}", s1);
println!("Mmm, {}", s2);
Cookies! Mmm, Cookies!
fn main() {
let cookies = String::from("Cookies!");
let s1: &str = &cookies;
let s2: &str = s1;

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

Въпроси