Псевдоними, низове, композирани типове
09 октомври 2018
Административни неща
- Инсталирайте си Rust: https://2017.fmi.rust-lang.bg/topics/2
Административни неща
- Инсталирайте си Rust: https://2017.fmi.rust-lang.bg/topics/2
- Елате в Discord канала: https://discord.gg/FCTNfbZ
Административни неща
- Инсталирайте си Rust: https://2017.fmi.rust-lang.bg/topics/2
- Елате в Discord канала: https://discord.gg/FCTNfbZ
- Регистрирайте се в https://fmi.rust-lang.bg!
Въпрос 1
Къде е грешката?
let x = 3;
let y = 5_i32;
x = x + y;
println!("{}", x);
Въпрос 1
Къде е грешката?
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
Къде е грешката?
let x = 3;
let y = 5_i32;
let x = x + y;
println!("{}", x);
8
Въпрос 2
Къде е грешката?
let x = 3.14_f32 as u32;
let y = 5_i32;
let z = x + y;
println!("{}", z);
Въпрос 2
Къде е грешката?
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
Къде е грешката?
let x = 3.14_f32 as u32;
let y = 5_i32;
let z = (x as u8) + (y as u8);
println!("{}", z);
8
Преговор
- Инсталация и подкарване (
rustup
,cargo
, Rust Playground)
Преговор
- Инсталация и подкарване (
rustup
,cargo
, Rust Playground) - Документация (The Rust Book,
rustup doc
)
Преговор
- Инсталация и подкарване (
rustup
,cargo
, Rust Playground) - Документация (The Rust Book,
rustup doc
) - Числа (конвертиране)
Преговор
- Инсталация и подкарване (
rustup
,cargo
, Rust Playground) - Документация (The Rust Book,
rustup doc
) - Числа (конвертиране)
- Променливи (отгатване на типове, скриване на променливи, мутация)
Преговор
- Инсталация и подкарване (
rustup
,cargo
, Rust Playground) - Документация (The Rust Book,
rustup doc
) - Числа (конвертиране)
- Променливи (отгатване на типове, скриване на променливи, мутация)
- Control flow (
if
,while
,loop
)
Преговор
- Инсталация и подкарване (
rustup
,cargo
, Rust Playground) - Документация (The Rust Book,
rustup doc
) - Числа (конвертиране)
- Променливи (отгатване на типове, скриване на променливи, мутация)
- Control flow (
if
,while
,loop
) - Функции (
fn
, връщане на стойности)
Преговор
- Инсталация и подкарване (
rustup
,cargo
, Rust Playground) - Документация (The Rust Book,
rustup doc
) - Числа (конвертиране)
- Променливи (отгатване на типове, скриване на променливи, мутация)
- Control flow (
if
,while
,loop
) - Функции (
fn
, връщане на стойности) - Твърдения и изрази (точка-и-запетаи!)
Преговор
- Инсталация и подкарване (
rustup
,cargo
, Rust Playground) - Документация (The Rust Book,
rustup doc
) - Числа (конвертиране)
- Променливи (отгатване на типове, скриване на променливи, мутация)
- Control flow (
if
,while
,loop
) - Функции (
fn
, връщане на стойности) - Твърдения и изрази (точка-и-запетаи!)
- Печатане на стандартния изход (
println!("x = {}", x)
)
Присвояване
let a = 7;
let b = a;
Присвояване
let a = 7;
let b = a;
println!("a = {}, b = {}", a, b);
a = 7, b = 7
Присвояване
let a = "Hello";
let b = a;
Присвояване
let a = "Hello";
let b = a;
println!("{}!", a);
println!("{} again!", b);
Hello! Hello again!
Присвояване
let s1 = String::from("Cookies!");
let s2 = s1;
Присвояване
let s1 = String::from("Cookies!");
let s2 = s1;
println!("{}", s1);
println!("Mmm, {}", s2);
Присвояване
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 използва семантика на местене
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()
let s1 = String::from("Cookies!");
let s2 = s1.clone();
println!("{}", s1);
println!("Mmm, {}", s2);
Cookies! Mmm, Cookies!
Низове
А защо това е проблем само при String
, а не при литералите?
Низове
Литерали
let s = "hello";
- Заделя се в статичната памет на програмата
- Непроменим (immutable)
String
let s = String::from("hello");
- Заделя се в динамичната памет
- Може да се променя (mutable)
Собственост и заемане
Собственост и заемане
Собственост
{
let a = 123;
// ...
}
Собственост и заемане
Собственост
{
let a = 123;
// ...
}
- Променливата
a
е валидна от декларацията до края на scope-a
Собственост и заемане
Собственост
{
let a = 123;
// ...
}
- Променливата
a
е валидна от декларацията до края на scope-a
Правила
Собственост и заемане
Собственост
{
let a = 123;
// ...
}
- Променливата
a
е валидна от декларацията до края на scope-a
Правила
- Всяка стойност в Rust си има собственик (owner)
Собственост и заемане
Собственост
{
let a = 123;
// ...
}
- Променливата
a
е валидна от декларацията до края на scope-a
Правила
- Всяка стойност в Rust си има собственик (owner)
- Стойността може да има само един собственик по всяко едно време
Собственост и заемане
Собственост
{
let a = 123;
// ...
}
- Променливата
a
е валидна от декларацията до края на scope-a
Правила
- Всяка стойност в Rust си има собственик (owner)
- Стойността може да има само един собственик по всяко едно време
- Когато собственикът излезе от scope, стойността се инвалидира/деалокира (подобно на деструктор)
Собственост
Функции
При подаването на аргументи към функция важат същите семантики
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 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
Собственост
Функции
Връщане на стойност от функция също може да прехвърля собственост
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)
}
The length of 'hello' is 5.
Собственост и заемане
Заемане (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()
}
The length of 'hello' is 5.
Псевдоними
Представяне
Псевдоними
Непроменим псевдоним (immutable reference)
fn main() {
let s = String::from("hello");
change(&s);
println!("{}", s);
}
fn change(some_string: &String) {
some_string.push_str(", world");
}
Псевдоними
Непроменим псевдоним (immutable reference)
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)
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
Псевдоними
Правила
- По всяко време може да съществува само едно от следните:
- точно един mutable псевдоним
- произволен брой immutable псевдоними
- Псевдонимите винаги са валидни
Псевдоними
Borrow checker
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
Псевдоними
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_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
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;
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
Псевдоними
Валидност
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
- псевдонимът винаги сочи към валидна инстанция (няма null псевдоним)
Псевдоними
Валидност
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
- псевдонимът винаги сочи към валидна инстанция (няма null псевдоним)
- не можем да местим инстанция докато е заета (borrowed)
Псевдоними
Валидност
let r;
{
let s = String::from("hello");
r = &s;
}
println!("{}", r);
Псевдоними
Валидност
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
Псевдоними
Валидност
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
Псевдонимът не може да надживее обекта, към който сочи
Псевдоними
let s = String::from("first");
let r = &s;
let s = String::from("second");
println!("{}", r);
println!("{}", s);
Псевдоними
let s = String::from("first");
let r = &s;
let s = String::from("second");
println!("{}", r);
println!("{}", s);
first second
Псевдоними
let s = String::from("hello");
let s = &s;
println!("{}", s);
Псевдоними
let s = String::from("hello");
let s = &s;
println!("{}", s);
hello