Структури, модули
13 октомври 2022
Преговор
Преговор
- Присвояване и местене; Clone и Copy
Преговор
- Присвояване и местене; Clone и Copy
- Собственост (ownership) и заемане (borrowing)
Преговор
- Присвояване и местене; Clone и Copy
- Собственост (ownership) и заемане (borrowing)
- Референции
Преговор
- Присвояване и местене; Clone и Copy
- Собственост (ownership) и заемане (borrowing)
- Референции
- референцията винаги сочи към валидна стойност
Преговор
- Присвояване и местене; Clone и Copy
- Собственост (ownership) и заемане (borrowing)
- Референции
- референцията винаги сочи към валидна стойност
- или произволен брой
&T, или точно една&mut T
Преговор
- Присвояване и местене; Clone и Copy
- Собственост (ownership) и заемане (borrowing)
- Референции
- референцията винаги сочи към валидна стойност
- или произволен брой
&T, или точно една&mut T
- Низове (
String) и резени от низове (&str)
Преговор
- Присвояване и местене; Clone и Copy
- Собственост (ownership) и заемане (borrowing)
- Референции
- референцията винаги сочи към валидна стойност
- или произволен брой
&T, или точно една&mut T
- Низове (
String) и резени от низове (&str) - Вектори (
Vec<T>) и резени от масиви (&[T])
Административни неща
- Предизвикателство 1 свърши
Структури

Структури
Синтаксис
struct User {
username: String,
email: String,
sign_in_count: u64,
}
struct User {
username: String,
email: String,
sign_in_count: u64,
}
fn main() {}
Структури
Създаване на инстанция
struct User {
username: String,
email: String,
sign_in_count: u64
}
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
}
struct User {
username: String,
email: String,
sign_in_count: u64
}
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
}
Структури
Достъп до полета
struct User {
username: String,
email: String,
sign_in_count: u64
}
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
println!("{}, {}", user.username, user.email);
Иванчо, ivan40@abv.bg
fn main() {
struct User {
username: String,
email: String,
sign_in_count: u64
}
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
println!("{}, {}", user.username, user.email);
}
Структури
Достъп до полета
Полетата се достъпват по същия начин и през референция.
Автоматично се правят необходимия брой дереференцирания.
struct User {
username: String,
email: String,
sign_in_count: u64
}
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let user_ref = &user;
println!("{}, {}", user_ref.username, user_ref.email);
Иванчо, ivan40@abv.bg
fn main() {
struct User {
username: String,
email: String,
sign_in_count: u64
}
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let user_ref = &user;
println!("{}, {}", user_ref.username, user_ref.email);
}
Структури
Промяна на полетата
Можем да променяме стойността на полетата, ако инстанцията е дефинирана като mut.
struct User {
username: String,
email: String,
sign_in_count: u64
}
let mut user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
user.email = "ivan40.ivanov@abv.bg".to_string();
println!("{}, {}", user.username, user.email);
Иванчо, ivan40.ivanov@abv.bg
fn main() {
struct User {
username: String,
email: String,
sign_in_count: u64
}
let mut user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
user.email = "ivan40.ivanov@abv.bg".to_string();
println!("{}, {}", user.username, user.email);
}
Структури
Преместване на структури
По подразбиране структурите се преместват (защото не имплементират Copy).
struct User {
username: String,
email: String,
sign_in_count: u64
}
let user1 = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let user2 = user1;
println!("user1 = {}, {}", user1.username, user1.email);
println!("user2 = {}, {}", user2.username, user2.email);
error[E0382]: borrow of moved value: `user1` --> src/bin/main_b3c03fba678cada8014f8bd9534eee85648a700d.rs:16:44 | 8 | let user1 = User { | ----- move occurs because `user1` has type `User`, which does not implement the `Copy` trait ... 14 | let user2 = user1; | ----- value moved here 15 | 16 | println!("user1 = {}, {}", user1.username, user1.email); | ^^^^^^^^^^^ 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) For more information about this error, try `rustc --explain E0382`. error: could not compile `rust` due to previous error
fn main() {
struct User {
username: String,
email: String,
sign_in_count: u64
}
let user1 = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let user2 = user1;
println!("user1 = {}, {}", user1.username, user1.email);
println!("user2 = {}, {}", user2.username, user2.email);
}
Структури
Клониране на структури
За да можем да създаваме копия на нашата структура, тя трябва да имплементира trait-а Clone.
Чрез атрибута #[derive(Clone)] компилатора автоматично ще ни създаде имплементация на Clone.
Аналогично #[derive(Copy)] ще имплементира Copy - но трябва всички полета да са Copy.
#[derive(Clone)]
struct User {
username: String,
email: String,
sign_in_count: u64
}
let user1 = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let user2 = user1.clone();
println!("user1 = {}, {}", user1.username, user1.email);
println!("user2 = {}, {}", user2.username, user2.email);
user1 = Иванчо, ivan40@abv.bg user2 = Иванчо, ivan40@abv.bg
fn main() {
#[derive(Clone)]
struct User {
username: String,
email: String,
sign_in_count: u64
}
let user1 = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let user2 = user1.clone();
println!("user1 = {}, {}", user1.username, user1.email);
println!("user2 = {}, {}", user2.username, user2.email);
}
Структури
Принтиране на структури
Аналогично можем да използваме атрибута #[derive(Debug)] за да получим имплементация на trait-а Debug.
Това ни позволява да принтираме нашата структура с println! инползвайки placeholder {:?}.
#[derive(Clone, Debug)]
struct User {
username: String,
email: String,
sign_in_count: u64
}
let user1 = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let user2 = user1.clone();
println!("user1 = {:?}", user1);
println!("user2 = {:?}", user2);
user1 = User { username: "Иванчо", email: "ivan40@abv.bg", sign_in_count: 10 } user2 = User { username: "Иванчо", email: "ivan40@abv.bg", sign_in_count: 10 }
fn main() {
#[derive(Clone, Debug)]
struct User {
username: String,
email: String,
sign_in_count: u64
}
let user1 = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let user2 = user1.clone();
println!("user1 = {:?}", user1);
println!("user2 = {:?}", user2);
}
Структури
Struct update синтаксис
Можем да дадем стойност само на част от полетата и останалите да попълним от друга инстанция
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let hacker = User {
email: String::from("hackerman@l33t.hax"),
..user
};
println!("{:?}", hacker);
User { username: "Иванчо", email: "hackerman@l33t.hax", sign_in_count: 10 }
#[derive(Debug)]
struct User { username: String, email: String, sign_in_count: u64 }
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let hacker = User {
email: String::from("hackerman@l33t.hax"),
..user
};
println!("{:?}", hacker);
}
Структури
Struct update синтаксис
Това ще премести полетата от оригиналната инстанция
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let hacker = User {
email: String::from("hackerman@l33t.hax"),
..user
};
println!("{:?}", hacker);
println!("{:?}", user);
error[E0382]: borrow of partially moved value: `user` --> src/bin/main_99773612f004f2399763eb71a56006b2f8c4c270.rs:16:18 | 10 | let hacker = User { | ______________- 11 | | email: String::from("hackerman@l33t.hax"), 12 | | ..user 13 | | }; | |_- value partially moved here ... 16 | println!("{:?}", user); | ^^^^ value borrowed here after partial move | = note: partial move occurs because `user.username` 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` due to previous error
#[derive(Debug)]
struct User { username: String, email: String, sign_in_count: u64 }
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
let hacker = User {
email: String::from("hackerman@l33t.hax"),
..user
};
println!("{:?}", hacker);
println!("{:?}", user);
}
Структури
Struct update синтаксис
Синтаксиса е удобен за попълване на стойности по подразбиране.
Напр. ако структурата имплементира трейта Default можем да използваме функцията default.
let user = User {
username: String::from("Иванчо"),
..User::default()
};
println!("{:?}", user);
User { username: "Иванчо", email: "", sign_in_count: 0 }
#[derive(Debug, Default)]
struct User { username: String, email: String, sign_in_count: u64 }
fn main() {
let user = User {
username: String::from("Иванчо"),
..User::default()
};
println!("{:?}", user);
}
Структури
Кратък синтаксис за създаване на структури
Често се случва стойността на поле да се задава чрез променлива със същото име. Има кратък синтаксис за това.
struct Rectangle {
width: f64,
height: f64,
}
let width = 2.0;
let height = 3.0;
// пълен синтаксис
let rect = Rectangle {
width: width,
height: height,
};
fn main() {
struct Rectangle {
width: f64,
height: f64,
}
let width = 2.0;
let height = 3.0;
// пълен синтаксис
let rect = Rectangle {
width: width,
height: height,
};
}
Структури
Кратък синтаксис за създаване на структури
Често се случва стойността на поле да се задава чрез променлива със същото име. Има кратък синтаксис за това.
struct Rectangle {
width: f64,
height: f64,
}
let width = 2.0;
let height = 3.0;
// кратък синтаксис
let rect = Rectangle {
width,
height,
};
fn main() {
struct Rectangle {
width: f64,
height: f64,
}
let width = 2.0;
let height = 3.0;
// кратък синтаксис
let rect = Rectangle {
width,
height,
};
}
Методи и асоциирани функции
Асоциирани функции
Методи и асоциирани функции
Асоциирани функции
struct User { ... }
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
fn main() {}
struct User { username: String, email: String, sign_in_count: u64 }
/*
struct User { ... }
*/
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
Методи и асоциирани функции
Асоциирани функции
struct User { ... }
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
fn main() {}
struct User { username: String, email: String, sign_in_count: u64 }
/*
struct User { ... }
*/
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
structблока съдържа само полетата на структурата
Методи и асоциирани функции
Асоциирани функции
struct User { ... }
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
fn main() {}
struct User { username: String, email: String, sign_in_count: u64 }
/*
struct User { ... }
*/
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
structблока съдържа само полетата на структурата- методи и функции се добавят в отделен
implблок
Методи и асоциирани функции
Асоциирани функции
struct User { ... }
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
fn main() {}
struct User { username: String, email: String, sign_in_count: u64 }
/*
struct User { ... }
*/
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
structблока съдържа само полетата на структурата- методи и функции се добавят в отделен
implблок - разделение между данни и логика
Методи и асоциирани функции
Асоциирани функции
struct User { ... }
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
let user = User::new(String::from("Иванчо"), String::from("ivan40@abv.bg"));
struct User { username: String, email: String, sign_in_count: u64 }
/*
struct User { ... }
*/
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
fn main() {
let user = User::new(String::from("Иванчо"), String::from("ivan40@abv.bg"));
}
Методи и асоциирани функции
Асоциирани функции
struct User { ... }
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
let user = User::new(String::from("Иванчо"), String::from("ivan40@abv.bg"));
struct User { username: String, email: String, sign_in_count: u64 }
/*
struct User { ... }
*/
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
fn main() {
let user = User::new(String::from("Иванчо"), String::from("ivan40@abv.bg"));
}
- функцията
newсе нарича асоциирана функция - семантично еднаква със статичен метод от други езици - когато викаме асоциирани функции като
new, трябва да ги префиксираме с името на структурата (User) и оператора::
Методи и асоциирани функции
Конструктори и деструктори
Методи и асоциирани функции
Конструктори и деструктори
- в Rust няма конструктори
Методи и асоциирани функции
Конструктори и деструктори
- в Rust няма конструктори
- конвенция е да има асоциирана функция, която създава обект от типа
Методи и асоциирани функции
Конструктори и деструктори
- в Rust няма конструктори
- конвенция е да има асоциирана функция, която създава обект от типа
- обикновенно името е
newfrom_*with_*
Методи и асоциирани функции
Конструктори и деструктори
- в Rust няма конструктори
- конвенция е да има асоциирана функция, която създава обект от типа
- обикновенно името е
newfrom_*with_*
- но има и изключения, напр.
File::open
Методи и асоциирани функции
Конструктори и деструктори
- в Rust има деструктори
- дефинират се чрез trait-а
Drop - за тях ще говорим по-късно
Методи и асоциирани функции
Типа Self
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
}
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
}
fn main() {}
Методи и асоциирани функции
Типа Self
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
}
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
}
fn main() {}
- достъпен само в
implблок
Методи и асоциирани функции
Типа Self
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
}
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
}
fn main() {}
- достъпен само в
implблок - alias на типа, за който имплементираме
Методи и асоциирани функции
Методи
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {}
Методи и асоциирани функции
Методи
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {}
- функция, която приема като първи аргумент
self,&self,&mut self(method receiver)
Методи и асоциирани функции
Методи
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {}
- функция, която приема като първи аргумент
self,&self,&mut self(method receiver) selfе еквивалентно наself: Self
Методи и асоциирани функции
Методи
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {}
- функция, която приема като първи аргумент
self,&self,&mut self(method receiver) selfе еквивалентно наself: Self&selfе еквивалентно наself: &Self
Методи и асоциирани функции
Методи
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {}
- функция, която приема като първи аргумент
self,&self,&mut self(method receiver) selfе еквивалентно наself: Self&selfе еквивалентно наself: &Self&mut selfе еквивалентно наself: &mut Self
Методи и асоциирани функции
Методи
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {}
- функция, която приема като първи аргумент
self,&self,&mut self(method receiver) selfе еквивалентно наself: Self&selfе еквивалентно наself: &Self&mut selfе еквивалентно наself: &mut Self
- полетата се достъпват през променливата
self
Методи и асоциирани функции
Методи
Могат да се извикват със синтаксиса за методи
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();
println!("area = {}", area);
area = 6
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self { Self { width, height } }
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();
println!("area = {}", area);
}
Методи и асоциирани функции
Методи
Могат да се извикват със синтаксиса за методи
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();
println!("area = {}", area);
area = 6
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self { Self { width, height } }
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();
println!("area = {}", area);
}
- както полетата, методите се достъпват с
.
Методи и асоциирани функции
Методи
Могат да се извикват със синтаксиса за методи
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();
println!("area = {}", area);
area = 6
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self { Self { width, height } }
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();
println!("area = {}", area);
}
- както полетата, методите се достъпват с
. - компилаторът автоматично добавя
*,&или&mut, така че типа на аргумента да съвпадне с типа на method receiver-а
Методи и асоциирани функции
Методи
Могат да се извикват и като асоциирани функции
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
let rect = Rectangle::new(2.0, 3.0);
let area = Rectangle::area(&rect);
println!("area = {}", area);
area = 6
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self { Self { width, height } }
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle::new(2.0, 3.0);
let area = Rectangle::area(&rect);
println!("area = {}", area);
}
Методи и асоциирани функции
Множество impl блокове
Позволено е декларирането на повече от един impl блок. Удобно е при групиране на методи.
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
impl Rectangle {
fn perimeter(&self) -> f64 {
2.0 * (self.width + self.height)
}
}
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
impl Rectangle {
fn perimeter(&self) -> f64 {
2.0 * (self.width + self.height)
}
}
fn main() {}
Tuples
(преговор)
(A, B, C, ...)
let tuple: (i32, u32, bool) = (1, 2, false);
println!("{}", tuple.0);
println!("{}", tuple.1);
println!("{}", tuple.2);
1 2 false
fn main() {
let tuple: (i32, u32, bool) = (1, 2, false);
println!("{}", tuple.0);
println!("{}", tuple.1);
println!("{}", tuple.2);
}
Tuple structs
Именувани кортежи
struct Color(f32, f32, f32);
struct Point(f32, f32, f32);
let black = Color(0.0, 0.0, 0.0);
let origin = Point(0.0, 0.0, 0.0);
fn main() {
struct Color(f32, f32, f32);
struct Point(f32, f32, f32);
let black = Color(0.0, 0.0, 0.0);
let origin = Point(0.0, 0.0, 0.0);
}
Tuple structs
Полетата се достъпват с .0, .1, и т.н., както при нормален tupple
struct Color(f32, f32, f32);
let black = Color(0.0, 0.0, 0.0);
println!("r: {}, g: {}, b: {}", black.0, black.1, black.2);
r: 0, g: 0, b: 0
fn main() {
struct Color(f32, f32, f32);
let black = Color(0.0, 0.0, 0.0);
println!("r: {}, g: {}, b: {}", black.0, black.1, black.2);
}
Tuple structs
Newtype wrapper
Tuple struct с едно поле често се използва за typesafe wrapper.
Това се нарича newtype struct или newtype wrapper.
#[derive(Debug, Clone, Copy)]
struct Token(u32);
#[derive(Debug, Clone, Copy)]
struct Token(u32);
fn main() {}
Празни структури
Възможна е декларацията на празни структури. Могат да се използват като маркери - големината им е 0 байта.
struct Electron {}
struct Proton;
let x = Electron {};
let y = Proton;
fn main() {
struct Electron {}
struct Proton;
let x = Electron {};
let y = Proton;
}
Модули

Модули
- начин да си организираме кода в отделни namespaces
Модули
- начин да си организираме кода в отделни namespaces
- обикновенно йерархията от модули съвпада с йерархията на файловете на проекта ни
Модули
Нека си създадем библиотека:
$ cargo new communicator --lib
communicator
├── Cargo.toml
└── src
└── lib.rs
Модули
- главния файл на проекта ни е и главния модул
- src/main.rs
- src/lib.rs
Модули
Можем да дефинираме подмодули в същия файл
// src/lib.rs
mod network {
fn init() { /* ... */ }
}
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() { /* ... */ }
}
mod client {
fn connect() { /* ... */ }
}
fn main() {}
Модули
Можем да дефинираме подмодули и в отделни файлове
communicator
├── Cargo.toml
└── src
├── client.rs
├── lib.rs
└── network.rs
- декларираме подмодулите с
mod MOD_NAME;
// src/lib.rs
mod network;
mod client;
Модули
Можем да дефинираме подмодули и в отделни файлове
communicator
├── Cargo.toml
└── src
├── client.rs
├── lib.rs
└── network.rs
- декларираме подмодулите с
mod MOD_NAME;
// src/lib.rs
mod network;
mod client;
- компилатора търси файл
./MOD_NAME.rsили./MOD_NAME/mod.rs
// src/network.rs
fn init() { /* ... */ }
// src/client.rs
fn connect() { /* ... */ }
Модули
Можем да имаме няколко нива на подмодули
// src/lib.rs
mod network {
fn init() { /* ... */ }
mod client {
fn connect() { /* ... */ }
}
}
mod network {
fn init() { /* ... */ }
mod client {
fn connect() { /* ... */ }
}
}
fn main() {}
Модули
Ако искаме да са в отделни файлове трябва да използваме директории
communicator
├── Cargo.toml
└── src
├── lib.rs
└── network
├── client.rs
└── mod.rs
// src/lib.rs
mod network;
// src/network/mod.rs
mod client;
fn init() { /* ... */ }
// src/network/client.rs
fn connect() { /* ... */ }
Модули
network модула може да го сложим или в src/network/mod.rs, или в src/network.rs
communicator
├── Cargo.toml
└── src
├── lib.rs
├── network.rs
└── network
└── client.rs
// src/lib.rs
mod network;
// src/network.rs
mod client;
fn init() { /* ... */ }
// src/network/client.rs
fn connect() { /* ... */ }
Достъп
В модул имаме директен достъп до всичко останало дефинирано в модула
mod client {
fn connect() { /* ... */ }
fn init() {
// client::connect();
connect();
}
}
mod client {
fn connect() { /* ... */ }
fn init() {
// client::connect();
connect();
}
}
fn main() {}
Достъп
Ако искаме да използваме нещо извън модула трябва да използваме пълното име или да го импортираме
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() {
crate::client::connect();
}
}
Достъп
- пълното име започва с ключовата дума
crate, ако е дефинирано в нашия проектcrate::some_module::some_item
Достъп
- пълното име започва с ключовата дума
crate, ако е дефинирано в нашия проектcrate::some_module::some_item
- или с името на библиотеката (crate-а), ако е дефинирано извън проекта
::std::vec::Vec::external_crate::some_module::some_item
Достъп
- пълното име започва с ключовата дума
crate, ако е дефинирано в нашия проектcrate::some_module::some_item
- или с името на библиотеката (crate-а), ако е дефинирано извън проекта
::std::vec::Vec::external_crate::some_module::some_item
- Освен това външните библиотеки са автоматично импортирани и могат да се използват директно, без началните
::std::vec::Vecexternal_crate::some_module::some_item
Достъп
Mоже да използваме self::... или super::... за релативен път
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() {
super::client::connect();
}
}
mod network {
mod client {
fn connect() { /* ... */ }
}
fn init() {
self::client::connect();
// или просто
client::connect();
}
}
#![allow(unused_imports)]
mod network {
mod client {
pub
fn connect() { /* ... */ }
}
fn init() {
self::client::connect();
// или просто
client::connect();
}
}
fn main() {}Достъп
Можем да използваме use за да импортираме имена от друг модул
mod client {
fn connect() { /* ... */ }
}
mod network {
use crate::client::connect;
fn init() {
connect();
}
}
mod client {
pub
fn connect() { /* ... */ }
}
mod network {
use crate::client::connect;
fn init() {
connect();
}
}
fn main() {}
Достъп
Можем да използваме use за да импортираме имена от друг модул
mod client {
fn connect() { /* ... */ }
}
mod network {
use crate::client::connect;
fn init() {
connect();
}
}
mod client {
pub
fn connect() { /* ... */ }
}
mod network {
use crate::client::connect;
fn init() {
connect();
}
}
fn main() {}
- ако искаме да импортираме повече от едно нещо:
use crate::client::{something, some_other_thing}
Достъп
Можем да използваме use за да импортираме имена от друг модул
mod client {
fn connect() { /* ... */ }
}
mod network {
use crate::client::connect;
fn init() {
connect();
}
}
mod client {
pub
fn connect() { /* ... */ }
}
mod network {
use crate::client::connect;
fn init() {
connect();
}
}
fn main() {}
- ако искаме да импортираме повече от едно нещо:
use crate::client::{something, some_other_thing} - или ако искаме да импортираме всичко от даден модул:
use crate::client::*(удобно заpreludeмодули или тестове)
Достъп: public и private
Ако искаме да използваме нещо извън модула, то трябва да е публично достъпно.
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() {
crate::client::connect();
}
}
error[E0603]: function `connect` is private --> src/bin/main_a59bcd63cbe47ef3a59fd915c88b119df8fb898a.rs:8:24 | 8 | crate::client::connect(); | ^^^^^^^ private function | note: the function `connect` is defined here --> src/bin/main_a59bcd63cbe47ef3a59fd915c88b119df8fb898a.rs:2:5 | 2 | fn connect() { /* ... */ } | ^^^^^^^^^^^^ For more information about this error, try `rustc --explain E0603`. error: could not compile `rust` due to previous error
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() {
crate::client::connect();
}
}
fn main() {}
Достъп: public и private
Ако искаме да използваме нещо извън модула, то трябва да е публично достъпно.
mod client {
pub fn connect() { /* ... */ }
// ^^^
}
mod network {
fn init() {
crate::client::connect();
}
}
mod client {
pub fn connect() { /* ... */ }
// ^^^
}
mod network {
fn init() {
crate::client::connect();
}
}
fn main() {}
Достъп: public и private
- в даден модул
- няма нива на достъп - винаги може да се достъпи всичко, което е дефинирано в текущия модул, или по-нагоре в йерархията
- (функции, структури, полета, методи, подмодули)
Достъп: public и private
- в даден модул
- няма нива на достъп - винаги може да се достъпи всичко, което е дефинирано в текущия модул, или по-нагоре в йерархията
- (функции, структури, полета, методи, подмодули)
- извън даден модул
- по подразбиране всичко е private
- за да се направи достъпно се използва ключовата дума
pub - за да се направи публично в рамките на crate-а, но недостъпно отвън, се използва
pub(crate)
Достъп: public и private
Структурата трябва да се маркира pub, за да е видима отвън
mod db {
pub struct User {
// ^^^
username: String,
email: String,
}
}
use self::db::User;
fn main() {
}
#![allow(unused_imports)]
mod db {
pub struct User {
// ^^^
username: String,
email: String,
}
}
use self::db::User;
fn main() {
}
Достъп: public и private
Полета също трябва да се отбележат с pub, за да се могат да се използват.
mod db {
pub struct User {
pub username: String,
pub email: String,
// ^^^
}
}
use self::db::User;
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
};
}
mod db {
pub struct User {
pub username: String,
pub email: String,
// ^^^
}
}
use self::db::User;
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
};
}
Достъп: public и private
Без проблем може да достъпим private полета от същия модул в който е дефинирана структурата
mod db {
pub struct User {
username: String,
email: String,
}
// свободна функция, не се намира в `impl` блок
pub fn make_user(username: String, email: String) -> User {
User { username, email }
}
}
fn main() {
let user = db::make_user(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
}
mod db {
pub struct User {
username: String,
email: String,
}
// свободна функция, не се намира в `impl` блок
pub fn make_user(username: String, email: String) -> User {
User { username, email }
}
}
fn main() {
let user = db::make_user(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
}
Достъп: public и private
Както и без проблем може да достъпим private полета на по-горен подмодул
mod db {
pub struct User {
username: String,
email: String,
}
pub mod make {
use super::User;
pub fn user(username: String, email: String) -> User {
User { username, email }
}
}
}
fn main() {
let user = db::make::user(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
}
mod db {
pub struct User {
username: String,
email: String,
}
pub mod make {
use super::User;
pub fn user(username: String, email: String) -> User {
User { username, email }
}
}
}
fn main() {
let user = db::make::user(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
}
Достъп: public и private
Но ако модулите са съседни не можем
mod db {
mod dto {
pub struct User {
username: String,
email: String,
}
}
pub mod make {
use super::dto::User;
pub fn user(username: String, email: String) -> User {
User { username, email }
}
}
}
error[E0451]: field `username` of struct `User` is private --> src/bin/main_28d9be0010e27078d5ad972d5e012c043a3b352b.rs:13:20 | 13 | User { username, email } | ^^^^^^^^ private field error[E0451]: field `email` of struct `User` is private --> src/bin/main_28d9be0010e27078d5ad972d5e012c043a3b352b.rs:13:30 | 13 | User { username, email } | ^^^^^ private field For more information about this error, try `rustc --explain E0451`. error: could not compile `rust` due to 2 previous errors
mod db {
mod dto {
pub struct User {
username: String,
email: String,
}
}
pub mod make {
use super::dto::User;
pub fn user(username: String, email: String) -> User {
User { username, email }
}
}
}
fn main() {}
Достъп: public и private
Тези правила важат и за tuple structs
mod product {
pub struct UserId(u64);
}
use self::product::UserId;
fn main() {
let id = UserId(123);
}
error[E0423]: cannot initialize a tuple struct which contains private fields --> src/bin/main_4ab3111369e2922d14fb54434dca1a25870e2bd1.rs:8:14 | 8 | let id = UserId(123); | ^^^^^^ | note: constructor is not visible here due to private fields --> src/bin/main_4ab3111369e2922d14fb54434dca1a25870e2bd1.rs:2:23 | 2 | pub struct UserId(u64); | ^^^ private field For more information about this error, try `rustc --explain E0423`. error: could not compile `rust` due to previous error
mod product {
pub struct UserId(u64);
}
use self::product::UserId;
fn main() {
let id = UserId(123);
}
Достъп: public и private
Тези правила важат и за tuple structs
mod product {
pub struct UserId(pub u64);
}
use self::product::UserId;
fn main() {
let id = UserId(123);
}
mod product {
pub struct UserId(pub u64);
}
use self::product::UserId;
fn main() {
let id = UserId(123);
}