Структури, модули
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 няма конструктори
- конвенция е да има асоциирана функция, която създава обект от типа
- обикновенно името е
new
from_*
with_*
Методи и асоциирани функции
Конструктори и деструктори
- в Rust няма конструктори
- конвенция е да има асоциирана функция, която създава обект от типа
- обикновенно името е
new
from_*
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::Vec
external_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); }