Присвояване, копиране, референции
14 октомври 2025
Материал
- стойности и собственост
- присвояване, копиране, референции
- borrow checker
- низове, масиви и резени
Структури
1
2
3
4
5
6
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
fn main() {
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
}
Структури
1
2
3
4
5
6
7
8
9
10
11
12
13
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@abv.bg".to_string(),
sign_in_count: 0,
};
fn main() {
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@abv.bg".to_string(),
sign_in_count: 0,
};
}
Структури
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@abv.bg".to_string(),
sign_in_count: 0,
};
println!("потребител: {} ({})", user1.first_name, user1.email);
потребител: Иван (ivancho444@abv.bg)
fn main() {
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@abv.bg".to_string(),
sign_in_count: 0,
};
println!("потребител: {} ({})", user1.first_name, user1.email);
}
Структури
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@abv.bg".to_string(),
sign_in_count: 0,
};
println!("{:?}", user1);
error[E0277]: `User` doesn't implement `Debug` --> src/bin/main_f19699da460375e8576d8cb60d89ab24d6d2823a.rs:16:18 | 16 | println!("{:?}", user1); | ---- ^^^^^ `User` cannot be formatted using `{:?}` because it doesn't implement `Debug` | | | required by this formatting parameter | = help: the trait `Debug` is not implemented for `User` = note: add `#[derive(Debug)]` to `User` or manually `impl Debug for User` = 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 annotating `User` with `#[derive(Debug)]` | 2 + #[derive(Debug)] 3 | struct User { | For more information about this error, try `rustc --explain E0277`. error: could not compile `rust` (bin "main_f19699da460375e8576d8cb60d89ab24d6d2823a") due to 1 previous error
fn main() {
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@abv.bg".to_string(),
sign_in_count: 0,
};
println!("{:?}", user1);
}
Структури
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#[derive(Debug)]
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
println!("{:?}", user1);
User { first_name: "Иван", last_name: "Иванов", email: "ivancho444@example.com", sign_in_count: 0 }
fn main() {
#[derive(Debug)]
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
println!("{:?}", user1);
}
Структури
derive
1
2
#[derive(Debug)]
struct User {
- анотация
- специален вид макрос
- имплентира някаква фунционалност за структурата
- в случая възможност да се принтира в репрезентация за дебъгване (
{:?})
Структури
1
2
3
4
5
6
7
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
println!("{:?}", user1);
User { first_name: "Иван", last_name: "Иванов", email: "ivancho444@example.com", sign_in_count: 0 }
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
println!("{:?}", user1);
}
Структури
1
2
3
4
5
6
7
8
9
10
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
println!("{:?}", user1);
let user2 = user1;
println!("{:?}", user2);
User { first_name: "Иван", last_name: "Иванов", email: "ivancho444@example.com", sign_in_count: 0 } User { first_name: "Иван", last_name: "Иванов", email: "ivancho444@example.com", sign_in_count: 0 }
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
println!("{:?}", user1);
let user2 = user1;
println!("{:?}", user2);
}
Структури
1
2
3
4
5
6
7
8
9
10
11
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
println!("{:?}", user1);
println!("{:?}", user2);
error[E0382]: borrow of moved value: `user1` --> src/bin/main_04e624f9edc54c80710388d5f588910334224916.rs:14:18 | 5 | let user1 = User { | ----- move occurs because `user1` has type `User`, which does not implement the `Copy` trait ... 12 | let user2 = user1; | ----- value moved here 13 | 14 | println!("{:?}", user1); | ^^^^^ value borrowed here after move | note: if `User` implemented `Clone`, you could clone the value --> src/bin/main_04e624f9edc54c80710388d5f588910334224916.rs:3:1 | 3 | struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 } | ^^^^^^^^^^^ consider implementing `Clone` for this type ... 12 | let user2 = user1; | ----- you could clone this value = 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) For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` (bin "main_04e624f9edc54c80710388d5f588910334224916") due to 1 previous error
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
println!("{:?}", user1);
println!("{:?}", user2);
}
Собственост
1
2
3
4
5
6
7
8
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
// let user2 = user1;
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
// let user2 = user1;
}
- променливата
user1има собственост над стойносттаUser { ... }
Собственост
1
2
3
4
5
6
7
8
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
}
- променливата
user1има собственост (ownership) над стойносттаUser { ... } - при присвояване стойността се прехвърля на променливата
user2
Собственост
1
2
3
4
5
6
7
8
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
}
- променливата
user1има собственост (ownership) над стойносттаUser { ... } - при присвояване стойността се прехвърля на променливата
user2 - след присвояването променливата
user1не съдържа стойност
Собственост
1
2
3
4
5
6
7
8
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
}
- променливата
user1има собственост (ownership) над стойносттаUser { ... } - при присвояване стойността се прехвърля на променливата
user2 - след присвояването променливата
user1не съдържа стойност - и не може да се достъпва
Собственост
1
2
3
4
5
6
7
8
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
}
- променливата
user1има собственост (ownership) над стойносттаUser { ... } - при присвояване стойността се прехвърля на променливата
user2 - след присвояването променливата
user1не съдържа стойност - и не може да се достъпва
- error: use of moved value
Собственост
1
2
3
4
5
6
7
8
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1;
}
- променливата
user1има собственост (ownership) над стойносттаUser { ... } - при присвояване стойността се прехвърля на променливата
user2 - след присвояването променливата
user1не съдържа стойност - и не може да се достъпва
- error: use of moved value
- това се нарича семантика на преместването (move semantics)
Собственост
Преместване
- една стойност винаги може да бъде преместена, ако имаме собственост над нея
Собственост
Преместване
- една стойност винаги може да бъде преместена, ако имаме собственост над нея
- преместването включва
Собственост
Преместване
- една стойност винаги може да бъде преместена, ако имаме собственост над нея
- преместването включва
- побитово копиране на стойността от едно място в паметта на друго
Собственост
Преместване
- една стойност винаги може да бъде преместена, ако имаме собственост над нея
- преместването включва
- побитово копиране на стойността от едно място в паметта на друго
- забравяне на старата памет
Собственост
Преместване
- една стойност винаги може да бъде преместена, ако имаме собственост над нея
- преместването включва
- побитово копиране на стойността от едно място в паметта на друго
- забравяне на старата памет
- операцията по копиране не може да бъде забранявана или модифицирана от програмиста
- (няма move constructor-и или подобни)
Собственост
Преместване
- повечето типове в езика използват семантика на преместването
- след присвояване, старата променлива не може да се иползва
1
2
3
4
5
let s1 = String::from("Hello");
let s2 = s1;
println!("{}", s2);
// println!("{}", s1); // грешка
Hello
fn main() {
let s1 = String::from("Hello");
let s2 = s1;
println!("{}", s2);
// println!("{}", s1); // грешка
}
Собственост
Копиране
- някои типове използват семантика на копирането
- при присвояване се прави побитово копие на стойността
- и и старата и новата променлива могат да се използват
- основно това са примитивни типове - числа, booleans, …
- тези типове се наричат
Copyтипове, защото имплементират traitCopy
- тези типове се наричат
1
2
3
4
5
let n1 = 123;
let n2 = n1;
println!("{}", n2);
println!("{}", n1);
123 123
fn main() {
let n1 = 123;
let n2 = n1;
println!("{}", n2);
println!("{}", n1);
}
Собственост
Клониране
- за останалите типове трябва експлицитно да направим копие на стойността
- това става с метода
.clone()
1
2
3
4
5
let s1 = String::from("Hello");
let s2 = s1.clone();
println!("{}", s2);
println!("{}", s1);
Hello Hello
fn main() {
let s1 = String::from("Hello");
let s2 = s1.clone();
println!("{}", s2);
println!("{}", s1);
}
Собственост
Клониране
.clone()създава изцяло нова стойност- промени по едната стойност не афектират другата
1
2
3
4
5
6
let s1 = String::from("Hello");
let mut s2 = s1.clone();
s2.push_str(", room");
println!("{}", s2);
println!("{}", s1);
Hello, room Hello
fn main() {
let s1 = String::from("Hello");
let mut s2 = s1.clone();
s2.push_str(", room");
println!("{}", s2);
println!("{}", s1);
}
Собственост
Клониране
- не всеки тип може да се клонира
- трябва да имплементира trait
Clone, който предоставя метода.clone()
1
2
3
4
5
6
7
8
9
10
11
12
13
#[derive(Debug)]
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
/* ... */
};
let user2 = user1.clone();
error[E0599]: no method named `clone` found for struct `User` in the current scope --> src/bin/main_969abe399b5aeac08a21f49af489d9cf76a659f1.rs:18:19 | 3 | struct User { | ----------- method `clone` not found for this struct ... 18 | let user2 = user1.clone(); | ^^^^^ method not found in `User` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `Clone` For more information about this error, try `rustc --explain E0599`. error: could not compile `rust` (bin "main_969abe399b5aeac08a21f49af489d9cf76a659f1") due to 1 previous error
fn main() {
#[derive(Debug)]
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1.clone();
}
Собственост
Клониране
- не всеки тип може да се клонира
- трябва да имплементира trait
Clone, който предоставя метода.clone() - най-лесно е да се имплементира с
deriveанотация
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#[derive(Clone)]
#[derive(Debug)]
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
/* ... */
};
let user2 = user1.clone();
fn main() {
#[derive(Clone)]
#[derive(Debug)]
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1.clone();
}
Собственост
Клониране
- не всеки тип може да се клонира
- трябва да имплементира trait
Clone, който предоставя метода.clone() - най-лесно е да се имплементира с
deriveанотация - няколко derive-а могат да се напишат на един ред
1
2
3
4
5
6
7
8
9
10
11
12
13
#[derive(Clone, Debug)]
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
/* ... */
};
let user2 = user1.clone();
fn main() {
#[derive(Clone, Debug)]
struct User {
first_name: String,
last_name: String,
email: String,
sign_in_count: u32,
}
let user1 = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user2 = user1.clone();
}
Собственост
Частично преместване
- възможно е да разпарчедосаме структура
- можем да преместим някои полета в отделни променливи
1
2
3
4
5
6
7
8
9
10
11
12
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let first_name = user1.first_name;
let last_name = user1.last_name;
println!("{} {}", first_name, last_name);
println!("{}", user1.email);
Иван Иванов ivancho444@example.com
fn main() {
#[derive(Clone, Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32, }
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let first_name = user1.first_name;
let last_name = user1.last_name;
println!("{} {}", first_name, last_name);
println!("{}", user1.email);
}
Собственост
Частично преместване
- но след това не можем да използваме оригиналната променлива в нейната цялост
- стойността се зачита за частично преместена
1
2
3
4
5
6
7
8
9
10
11
12
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let first_name = user1.first_name;
let last_name = user1.last_name;
println!("{} {}", first_name, last_name);
println!("{:?}", user1);
error[E0382]: borrow of partially moved value: `user1` --> src/bin/main_89121857f23d6145b09a167ad215fc546cb6cfee.rs:16:18 | 13 | let last_name = user1.last_name; | --------------- value partially moved here ... 16 | println!("{:?}", user1); | ^^^^^ value borrowed here after partial move | = note: partial move occurs because `user1.last_name` has type `String`, which does not implement the `Copy` trait = 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) For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` (bin "main_89121857f23d6145b09a167ad215fc546cb6cfee") due to 1 previous error
fn main() {
#[derive(Clone, Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32, }
let user1 = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let first_name = user1.first_name;
let last_name = user1.last_name;
println!("{} {}", first_name, last_name);
println!("{:?}", user1);
}
При функции
При функции
- семантиката на преместване се използва и когато подаваме аргументи на функции
1
2
3
4
5
6
7
8
9
10
fn print_user(user: User) {
println!("{:?}", user);
}
let user1 = User {
/* ... */
};
print_user(user1);
// print_user(user1);
User { first_name: "Иван", last_name: "Иванов", email: "ivancho444@example.com", sign_in_count: 0 }
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
fn print_user(user: User) {
println!("{:?}", user);
}
let user1 = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
print_user(user1);
// print_user(user1);
}
При функции
- семантиката на преместване се използва и когато подаваме аргументи на функции
1
2
3
4
5
6
7
8
9
10
fn print_user(user: User) {
println!("{:?}", user);
}
let user1 = User {
/* ... */
};
print_user(user1);
print_user(user1);
error[E0382]: use of moved value: `user1` --> src/bin/main_077f47614989244065d75a10ea5b7057f3c5819e.rs:18:12 | 9 | let user1 = User { | ----- move occurs because `user1` has type `User`, which does not implement the `Copy` trait ... 17 | print_user(user1); | ----- value moved here 18 | print_user(user1); | ^^^^^ value used here after move | note: consider changing this parameter type in function `print_user` to borrow instead if owning the value isn't necessary --> src/bin/main_077f47614989244065d75a10ea5b7057f3c5819e.rs:5:21 | 5 | fn print_user(user: User) { | ---------- ^^^^ this parameter takes ownership of the value | | | in this function note: if `User` implemented `Clone`, you could clone the value --> src/bin/main_077f47614989244065d75a10ea5b7057f3c5819e.rs:3:1 | 3 | struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 } | ^^^^^^^^^^^ consider implementing `Clone` for this type ... 17 | print_user(user1); | ----- you could clone this value For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` (bin "main_077f47614989244065d75a10ea5b7057f3c5819e") due to 1 previous error
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
fn print_user(user: User) {
println!("{:?}", user);
}
let user1 = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
print_user(user1);
print_user(user1);
}
Референции
- позволяват използване на стойност за определен период
- без да имаме собственост над стойността
Референции
- позволяват използване на стойност за определен период
- без да имаме собственост над стойността
- референция
&T- споделена референция / константна референция
- shared reference / immutable borrow
- тип
&T - взимане на референция:
let ref_x = &x; - дереференциране:
*ref_x;
Референции
1
2
3
4
5
6
7
8
9
10
fn print_user(user: &User) {
println!("потребител {} (влизания {})", user.email, user.sign_in_count);
}
let user1 = User {
/* ... */
};
print_user(&user1);
print_user(&user1);
потребител ivancho444@example.com (влизания 0) потребител ivancho444@example.com (влизания 0)
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
fn print_user(user: &User) {
println!("потребител {} (влизания {})", user.email, user.sign_in_count);
}
let user1 = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
print_user(&user1);
print_user(&user1);
}
Референции
1
2
3
4
5
6
7
8
9
10
11
fn print_user(user: &User) {
println!("потребител {} (влизания {})", user.email, user.sign_in_count);
}
let user1 = User {
/* ... */
};
let user_ref = &user1;
print_user(user_ref);
print_user(user_ref);
потребител ivancho444@example.com (влизания 0) потребител ivancho444@example.com (влизания 0)
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
fn print_user(user: &User) {
println!("потребител {} (влизания {})", user.email, user.sign_in_count);
}
let user1 = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user_ref = &user1;
print_user(user_ref);
print_user(user_ref);
}
Референции
- полета на структура се достъпват прозрачно през референция
1
2
3
user_ref.email
// еквивалентно на
(*user_ref).email
Референции
- достъпът до поле _синтактично_ връща стойност от типа на полето
1
user_ref.email // : String
Референции
- достъпът до поле _синтактично_ връща стойност от типа на полето
1
user_ref.email // : String
- но това би означавало да преместим стойността извън структурата
- което не е позволено през референция
1
2
3
4
5
6
let user1 = User {
/* ... */
};
let user_ref = &user1;
let email = user_ref.email;
error[E0507]: cannot move out of `user_ref.email` which is behind a shared reference --> src/bin/main_3cf3e95d06a467eb0d102ad03ce84f1b8be04798.rs:14:13 | 14 | let email = user_ref.email; | ^^^^^^^^^^^^^^ move occurs because `user_ref.email` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here | 14 | let email = &user_ref.email; | + help: consider cloning the value if the performance cost is acceptable | 14 | let email = user_ref.email.clone(); | ++++++++ For more information about this error, try `rustc --explain E0507`. error: could not compile `rust` (bin "main_3cf3e95d06a467eb0d102ad03ce84f1b8be04798") due to 1 previous error
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
let user1 = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user_ref = &user1;
let email = user_ref.email;
}
Референции
- обикновенно искаме да вземем референция към полето
1
&user_ref.email // : &String
1
2
3
4
5
6
7
8
let user1 = User {
/* ... */
};
let email = &user1.email;
println!("{:?}", user1);
println!("{:?}", email);
User { first_name: "Иван", last_name: "Иванов", email: "ivancho444@example.com", sign_in_count: 0 } "ivancho444@example.com"
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
let user1 = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let email = &user1.email;
println!("{:?}", user1);
println!("{:?}", email);
}
Референции
&Tе констнатна референция и позвалява само четене на стойността&mut Tпозволява и променяне на реферираната стойност
- референция
&mut T- ексклузивна референция / mutable референция
- unique reference / mutable borrow
- тип
&mut T - взимане на референция:
let ref_x = &mut x; - дереференциране:
*ref_x;
Референции
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fn check_and_sign_in(user: &mut User, email: &str) -> bool {
if user.email == email {
user.sign_in_count += 1;
true
} else {
false
}
}
let mut user1 = User {
/* ... */
};
print_user(&user1);
check_and_sign_in(&mut user1, "ivancho444@example.com");
print_user(&user1);
потребител ivancho444@example.com (влизания 0) потребител ivancho444@example.com (влизания 1)
fn main() {
#[derive(Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
fn print_user(user: &User) { println!("потребител {} (влизания {})", user.email, user.sign_in_count); }
fn check_and_sign_in(user: &mut User, email: &str) -> bool {
if user.email == email {
user.sign_in_count += 1;
true
} else {
false
}
}
let mut user1 = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
print_user(&user1);
check_and_sign_in(&mut user1, "ivancho444@example.com");
print_user(&user1);
}
Валидност
- референцията е указател - адрес в паметта
Валидност
- референцията е указател - адрес в паметта
- който не е null
Валидност
- референцията е указател - адрес в паметта
- който не е null
- който винаги сочи към валидна стойност
- алокирана и инициализирана
- жива - не е преместена или деалокиана след вземането на референцията
Валидност
- референцията е указател - адрес в паметта
- който не е null
- който винаги сочи към валидна стойност
- алокирана и инициализирана
- жива - не е преместена или деалокиана след вземането на референцията
- референциите в Rust са винаги валидни!
Валидност
- променливите са валидни до края на лексикографския scope
- на края на scope-а се извиква деструктор (ако има) и стойността се унищожава
- в обратния ред на декларирането им
1
2
3
4
5
6
7
fn main() {
let user1 = User { /* ... */ };
let user2 = User { /* ... */ };
} // <--+
// | - user2 се унищожава (извиква се деструктора)
// | - после user1 се унищожава
Валидност
- променливите са валидни до края на лексикографския scope *
1
2
3
4
5
6
7
8
fn main() {
let user1 = User { /* ... */ };
{
let user2 = User { /* ... */ };
} // <--+
// | - user2 се унищожава
} // <--+
// | - user1 се унищожава
Валидност
- референцията не може да надживява стойността, към която сочи
1
2
3
4
5
6
7
8
fn main() {
let user1 = User { /* ... */ };
{
let user_ref = &user1;
} // <--+
// | OK - user_ref се "унищожава" преди user1
}
Валидност
- референцията не може да надживява стойността, към която сочи
1
2
3
4
5
fn main() {
let user1 = User { /* ... */ };
let user_ref = &user1;
} // <--+
// | OK - user_ref се "унищожава" преди user1
Валидност
- референцията не може да надживява стойността, към която сочи
1
2
3
4
5
6
7
8
fn main() {
let user_ref = {
let user1 = User { /* ... */ };
&user1
}; // <--+
// | грешка - user1 се унищожава преди user_ref
}
Валидност
- по същата причина не можем от функция да върнем референция
- която сочи към нищото
1
2
3
4
5
6
7
8
9
10
fn make_user() -> &User {
let user = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
&user
}
error[E0106]: missing lifetime specifier --> src/bin/main_4a0106a2a87805b208db2b98da049f46c9c82709.rs:4:19 | 4 | fn make_user() -> &User { | ^ 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` | 4 | fn make_user() -> &'static User { | +++++++ help: instead, you are more likely to want to return an owned value | 4 - fn make_user() -> &User { 4 + fn make_user() -> User { | For more information about this error, try `rustc --explain E0106`. error: could not compile `rust` (bin "main_4a0106a2a87805b208db2b98da049f46c9c82709") due to 1 previous error
fn main() {}
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
fn make_user() -> &User {
let user = User {
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
&user
}
Валидност
- не можем да преместим стойност, ако съществува референция към нея
- защото това би инвалидирало референцията
1
2
3
4
5
6
7
8
9
10
let user = User {
/* ... */
};
let user_ref = &user;
// преместване от `user`
let new_user = user;
println!("{:?}", user_ref);
error[E0505]: cannot move out of `user` because it is borrowed --> src/bin/main_f4df860c7064493f3f5268cabeb09dd34b55a345.rs:16:16 | 5 | let user = User { | ---- binding `user` declared here ... 13 | let user_ref = &user; | ----- borrow of `user` occurs here ... 16 | let new_user = user; | ^^^^ move out of `user` occurs here 17 | 18 | println!("{:?}", user_ref); | -------- borrow later used here | help: consider cloning the value if the performance cost is acceptable | 13 | let user_ref = &user.clone(); | ++++++++ For more information about this error, try `rustc --explain E0505`. error: could not compile `rust` (bin "main_f4df860c7064493f3f5268cabeb09dd34b55a345") due to 1 previous error
#[derive(Clone, Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
fn main() {
let user = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user_ref = &user;
// преместване от `user`
let new_user = user;
println!("{:?}", user_ref);
}
Валидност
Non lexical lifetimes
- предишния пример всъщност се компилира
- ако премахнем последния
println
1
2
3
4
5
6
7
8
9
10
let user = User {
/* ... */
};
let user_ref = &user;
// преместване от `user`
let new_user = user;
// println!("{:?}", user_ref);
#[derive(Clone, Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
fn main() {
let user = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
let user_ref = &user;
// преместване от `user`
let new_user = user;
// println!("{:?}", user_ref);
}
Валидност
Non lexical lifetimes
- референциите не се унищожават в края на лексикографския scope
- референциите се считат за унищожени след последното място, където се използват
- предходния код е еквивалентен на
1
2
3
4
5
6
7
8
9
10
11
12
let user = User {
/* ... */
};
{
let user_ref = &user;
}
// преместване от `user`
let new_user = user;
// println!("{:?}", user_ref);
#[derive(Clone, Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
fn main() {
let user = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
{
let user_ref = &user;
}
// преместване от `user`
let new_user = user;
// println!("{:?}", user_ref);
}
Валидност
Non lexical lifetimes
- ако разкоментиваме
printlnизраза - референцията живее прекалено дълго
- и не позволява преместването от
user
1
2
3
4
5
6
7
8
9
10
11
12
let user = User {
/* ... */
};
{
let user_ref = &user;
// преместване от `user`
let new_user = user;
println!("{:?}", user_ref);
}
error[E0505]: cannot move out of `user` because it is borrowed --> src/bin/main_c2978216bc64735f29a51f1c97dcd28468a61c4e.rs:17:20 | 5 | let user = User { | ---- binding `user` declared here ... 14 | let user_ref = &user; | ----- borrow of `user` occurs here ... 17 | let new_user = user; | ^^^^ move out of `user` occurs here 18 | 19 | println!("{:?}", user_ref); | -------- borrow later used here | help: consider cloning the value if the performance cost is acceptable | 14 | let user_ref = &user.clone(); | ++++++++ For more information about this error, try `rustc --explain E0505`. error: could not compile `rust` (bin "main_c2978216bc64735f29a51f1c97dcd28468a61c4e") due to 1 previous error
#[derive(Clone, Debug)]
struct User { first_name: String, last_name: String, email: String, sign_in_count: u32 }
fn main() {
let user = User {
/* ... */
first_name: "Иван".to_string(),
last_name: "Иванов".to_string(),
email: "ivancho444@example.com".to_string(),
sign_in_count: 0,
};
{
let user_ref = &user;
// преместване от `user`
let new_user = user;
println!("{:?}", user_ref);
}
}
Borrow checker
Borrow checker
Правило
- По всяко време към една стойност може да съществува най-много едно от следните:
Borrow checker
Правило
- По всяко време към една стойност може да съществува най-много едно от следните:
- точно една екслкузивна референция (
&mut T)
- точно една екслкузивна референция (
Borrow checker
Правило
- По всяко време към една стойност може да съществува най-много едно от следните:
- точно една екслкузивна референция (
&mut T) - произволен брой споделени референции (
&T)
- точно една екслкузивна референция (
Borrow checker
Защо?
- голяма категория проблеми са породени от "shared mutable state"
Borrow checker
Защо?
- голяма категория проблеми са породени от "shared mutable state"
- data races при многонишкови програми
Borrow checker
Защо?
- голяма категория проблеми са породени от "shared mutable state"
- data races при многонишкови програми
- логически бъгове при еднонишкови
Borrow checker
Защо?
- голяма категория проблеми са породени от "shared mutable state"
- data races при многонишкови програми
- логически бъгове при еднонишкови
- невъзможност за локален анализ
Borrow checker
Защо?
- голяма категория проблеми са породени от "shared mutable state"
- data races при многонишкови програми
- логически бъгове при еднонишкови
- невъзможност за локален анализ
- някои езици (основно чисто функционалните) решават този проблем, като забраняват мутацията
- но това води до други неудобства
Borrow checker
Защо?
- голяма категория проблеми са породени от "shared mutable state"
- data races при многонишкови програми
- логически бъгове при еднонишкови
- невъзможност за локален анализ
- някои езици (основно чисто функционалните) решават този проблем, като забраняват мутацията
- но това води до други неудобства
- но това води до други неудобства
- Rust решава проблема, като забранява едновременното споделяне и мутация
- споделяне без мутация през
&T - мутация без споделяне през
&mut T
- споделяне без мутация през
Borrow checker
Цитат
Monads are a clever way to show you can program without mutation;
[Rust borrow rules] are an even cleverer way to show you can just use mutation
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);
}
}
}
Низове
Низове
String
Stringе тип, поддържащ собственост над динамично алокирано парче памет- чието съдържание е utf8 закодиран низ
- типа
Stringе структура с полетаptrlencap
Низове
Разполагане в паметта (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
- динамичен низ
- методи като
push(),pop() - съдържа буфер с определен капацитет
- автоматично се реалокира при превишаване на капацитета
1
2
3
4
5
6
let mut hello = String::from("Hello, ");
hello.push('w');
hello.push_str("orld!");
println!("{:?}", hello);
"Hello, world!"
fn main() {
let mut hello = String::from("Hello, ");
hello.push('w');
hello.push_str("orld!");
println!("{:?}", hello);
}
Низове
&str
&strе тип референция- указател към някакво парче памет
- чието съдържание е utf8 закодиран низ
- съдържа
ptrlen
Низове
Разполагане в паметта (&str)
1
2
let my_name = String::from("Pascal Precht");
let my_name_slice = my_name.as_str();
fn main() {
let my_name = String::from("Pascal Precht");
let my_name_slice = my_name.as_str();
}
[––––– my_name: String ––––] [my_name_slice: &str]
+––––––––+––––––––+––––––––+ +–––––––––+–––––––––+
stack frame │ ptr=• │ cap=16 │ len=13 │ │ ptr=• │ len=13 │
+–––––│––+––––––––+––––––––+ +––––––│––+–––––––––+
+––––+ │
│ +–––––––––––––––––––––––––––––––––+
│ │
│ │
[│–│––––––––––––––––––––– str ––––––––––––––––––––––]
+V–V+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+
heap │ P │ a │ s │ c │ a │ l │ ␣ │ P │ r │ e │ c │ h │ t │ │ │ │
+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+
Низове
&str
&str- string slice- immutable резен от низ
- през него може само да се прочете низа
Низове
&str
&str- string slice- immutable резен от низ
- през него може само да се прочете низа
&mut str- mutable string slice- mutable резен от низ
- през него може да се променя съдържанието на низа (отделни символи)
- но не могат да се махат или добавят символи
Низове
Литерали
- типа на низовете литерали също е
&str
1
let s: &str = "literal string";
Низове
Литерали
- типа на низовете литерали също е
&str
1
let s: &str = "literal string";
- те сочат към памет, която се притежава от "програмата"
- т.е. памет, която е заделена от операционната система
- при зареждане на програмата от файл в паметта
Низове
Литерали
- типа на низовете литерали също е
&str
1
let s: &str = "literal string";
- те сочат към памет, която се притежава от "програмата"
- т.е. памет, която е заделена от операционната система
- при зареждане на програмата от файл в паметта
1
let s: &'static str = "Hello";
- всъщност пълния тип е
&'static str, но това е тема за друг път
Низове
Резени
- резенът може да сочи към част от низ
1
2
3
4
5
6
7
let s = "Hello, world";
let hello = &s[0..5];
let world = &s[7..12];
println!("{:?}", s);
println!("{:?}", hello);
println!("{:?}", world);
"Hello, world" "Hello" "world"
fn main() {
let s = "Hello, world";
let hello = &s[0..5];
let world = &s[7..12];
println!("{:?}", s);
println!("{:?}", hello);
println!("{:?}", world);
}
Низове
Резени
- това не води до заделяне на нови низове
- само референция към вече алокирана памет
1
2
3
4
5
6
7
let s = "Hello, world";
let hello = &s[0..5];
let world = &s[7..12];
println!("{:12}: ptr={:#x} len={}", s, s.as_ptr() as usize, s.len());
println!("{:12}: ptr={:#x} len={}", hello, hello.as_ptr() as usize, hello.len());
println!("{:12}: ptr={:#x} len={}", world, world.as_ptr() as usize, world.len());
Hello, world: ptr=0x556339750c0b len=12 Hello : ptr=0x556339750c0b len=5 world : ptr=0x556339750c12 len=5
fn main() {
let s = "Hello, world";
let hello = &s[0..5];
let world = &s[7..12];
println!("{:12}: ptr={:#x} len={}", s, s.as_ptr() as usize, s.len());
println!("{:12}: ptr={:#x} len={}", hello, hello.as_ptr() as usize, hello.len());
println!("{:12}: ptr={:#x} len={}", world, world.as_ptr() as usize, world.len());
}
Низове
Разполагане в паметта (&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 │
+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+–––+
Низове
Интервали
- интервал
0..5- тип
Range - полуотворен интервал
[0; 5) = {0, 1, 2, 3, 4}
- тип
Низове
Интервали
- интервал
0..5- тип
Range - полуотворен интервал
[0; 5) = {0, 1, 2, 3, 4}
- тип
- интервал
0..=5- тип
RangeInclusive - затворен интервал
[0; 5] = {0, 1, 2, 3, 4, 5}
- тип
Низове
Интервали
- интервал
0..5- тип
Range - полуотворен интервал
[0; 5) = {0, 1, 2, 3, 4}
- тип
- интервал
0..=5- тип
RangeInclusive - затворен интервал
[0; 5] = {0, 1, 2, 3, 4, 5}
- тип
- други типове интервали
..5- от началото до 5 (без 5)..=5- от началото до 5 (включително)5..- от 5 до края..- от началото до края
Низове
Интервали
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
2
3
4
5
struct User {
first_name: String,
last_name: String,
email: String,
}
Низове
Използване
Кога да използвате &str?
- когато ви трябва само да прочетете дадена стойност
1
fn print_names(first: &str, last: &str) { /* ... */ }
- когато резултата е част от входните данни
1
fn trim_whitespace(s: &str) -> &str { /* ... */ }
Низове
Използване
format!макрото може да се използва за построяване на низ- поддържа същите placeholders като
println!
1
2
3
4
5
let hello = "hello";
let hello2 = format!("{}, again", hello); // : String
println!("{:?}", hello2);
"hello, again"
fn main() {
let hello = "hello";
let hello2 = format!("{}, again", hello); // : String
println!("{:?}", hello2);
}
Низове
Използване
1
2
3
4
5
6
7
8
// конвертиране от &str до String
let s = String::from("hello");
let s = "hello".to_string();
let s = "hello".to_owned();
// конвертиране от String до &str
let str_ref = s.as_str();
let str_ref = &s[..];
fn main() {
// конвертиране от &str до String
let s = String::from("hello");
let s = "hello".to_string();
let s = "hello".to_owned();
// конвертиране от String до &str
let str_ref = s.as_str();
let str_ref = &s[..];
}
Низове
Индексиране
str::lenвръща дължината на низ в брой байтове, не символи- при взимането на подрезен се оказват брой байтове
- за работа по символи трябва да се използва итератора
chars()
1
2
3
4
5
let hello = "Здравей свят";
println!("bytes {}", hello.len());
println!("chars {}", hello.chars().count());
println!("{:?}", &hello[..14]);
bytes 23 chars 12 "Здравей"
fn main() {
let hello = "Здравей свят";
println!("bytes {}", hello.len());
println!("chars {}", hello.chars().count());
println!("{:?}", &hello[..14]);
}
Низове
Индексиране
&strнизовете трябва винаги да съдържат валиден utf8- затова не е позволено всимане на резен по средата на символ
1
2
3
let hello = "Здравей свят";
println!("{:?}", &hello[..13]);
thread 'main' panicked at src/bin/main_3b57e62b952095839146965c2229e9511f8e078c.rs:4:24: byte index 13 is not a char boundary; it is inside 'й' (bytes 12..14) of `Здравей свят` note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
fn main() {
let hello = "Здравей свят";
println!("{:?}", &hello[..13]);
}
Низове
Индексиране
&strняма дефинирана операци за индексиране с число
1
2
3
let hello = "Здравей свят";
println!("{:?}", hello[2]);
error[E0277]: the type `str` cannot be indexed by `{integer}` --> src/bin/main_07697788709a48545e5e9b9d2fbc0083c5254bc1.rs:4:24 | 4 | println!("{:?}", hello[2]); | ^ string indices are ranges of `usize` | = help: the trait `SliceIndex<str>` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings> = help: the following other types implement trait `SliceIndex<T>`: `usize` implements `SliceIndex<ByteStr>` `usize` implements `SliceIndex<[T]>` = note: required for `str` to implement `Index<{integer}>` For more information about this error, try `rustc --explain E0277`. error: could not compile `rust` (bin "main_07697788709a48545e5e9b9d2fbc0083c5254bc1") due to 1 previous error
fn main() {
let hello = "Здравей свят";
println!("{:?}", hello[2]);
}
Масиви
Масиви
Типа [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>
- динамичен масив с елементи от тип
T - поддържа собственост над динамично алокирана памет
- структура с полета
ptrlencap
- методи като
push(),pop() - автоматично си разширява капацитета при добавяне на елементи
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>
- инициализация с макрото
vec! - поддържа същия синтаксис като инициализацията на статични масиви
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>
- инициализация с макрото
vec! - поддържа и инциализация с фиксирана стойност с
[<елемент>; <брой>]
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);
}
Масиви
Типа &[T]
- резен от масив (slice)
Масиви
Типа &[T]
- резен от масив (slice)
- репрезентация
ptrlen
Масиви
Типа &[T]
- резен от масив (slice)
- репрезентация
ptrlen
&[T]- immutable slice- може само да се прочете стойността на елементите
Масиви
Типа &[T]
- резен от масив (slice)
- репрезентация
ptrlen
&[T]- immutable slice- може само да се прочете стойността на елементите
&mut [T]- mutable slice- позволява променяне на отделен елемент (позволява взимане на
&mut Tкъм елемента) - не позволява добавяне или премахване на елементи
Масиви
Резени
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);
}
Масиви
Литерали
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
let mut v = vec![2, 4, 6, 8, 10, 12];
for elem in &mut v[1..4] {
*elem += 1;
}
println!("{:?}", v);
[2, 5, 7, 9, 10, 12]
fn main() {
let mut v = vec![2, 4, 6, 8, 10, 12];
for elem in &mut v[1..4] {
*elem += 1;
}
println!("{:?}", v);
}
Обобщение
| Масив | Низ | ||
|---|---|---|---|
| статичен | [T; N] |
- | собственост над стойността |
| динамичен | Vec<T> |
String |
собственост над стойността |
| резен | &[T] |
&str |
заета назаем стойност (borrow) |
| mutable резен | &mut [T] |
&mut str |
заета назаем стойност (borrow) |