Структури, модули, външни пакети
14 октомври 2020
Преговор
Преговор
- Присвояване и местене; 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 свърши
Съдържание
- Структури
- Методи
- Модули
- Използване на пакети от crates.io
Структури

Структури
Синтаксис
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
}
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
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,
};
}
Структури
Достъп до полета
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);
}
Структури
Struct update syntax
Можем да дадем стойност само на част от полетата и останалите да попълним от друга инстанция
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.username, hacker.email);
Иванчо, hackerman@l33t.hax
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.username, hacker.email);
}
Структури
Struct update syntax
Това ще премести полетата от оригиналната инстанция
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.username, hacker.email);
println!("{}, {}", user.username, user.email);
error[E0382]: borrow of moved value: `user.username` --> src/bin/main_209502704f19bd1ac614f06e4f28a71d4c84dc9b.rs:15:20 | 9 | let hacker = User { | ______________- 10 | | email: String::from("hackerman@l33t.hax"), 11 | | ..user 12 | | }; | |_- value moved here ... 15 | println!("{}, {}", user.username, user.email); | ^^^^^^^^^^^^^ value borrowed here after move | = note: move occurs because `user.username` has type `std::string::String`, which does not implement the `Copy` trait
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.username, hacker.email);
println!("{}, {}", user.username, user.email);
}
Структури
Кратък синтаксис за създаване на структури
Има кратък синтаксис ако стойността на поле се задава чрез променлива със същото име
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,
}
fn main() {
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,
};
struct Rectangle {
width: f64,
height: f64,
}
fn main() {
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блока съдържа само полетата на структурата- методи и функции се добавят в отделен
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
}
}
let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();
println!("{}", 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);
}
Методи и асоциирани функции
Методи
Могат да се извикват със синтаксиса за методи
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);
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);
}
- както полетата, методите се достъпват с
.
Методи и асоциирани функции
Методи
Могат да се извикват със синтаксиса за методи
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);
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);
}
- както полетата, методите се достъпват с
. - компилаторът автоматично добавя
*,&или&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);
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);
}
Методи и асоциирани функции
Множество 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() {}
Tuple structs
Именувани кортежи
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
fn main() {
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
}
Tuple structs
Полетата се достъпват с .0, .1, и т.н., както при нормален
struct Color(i32, i32, i32);
let black = Color(0, 0, 0);
println!("r: {}, g: {}, b: {}", black.0, black.1, black.2);
r: 0, g: 0, b: 0
fn main() {
struct Color(i32, i32, i32);
let black = Color(0, 0, 0);
println!("r: {}, g: {}, b: {}", black.0, black.1, black.2);
}
Празни структури
Възможна е декларацията на празни структури. Могат да се използват като маркери - големината им е 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 connect() {
// ...
}
}
mod client {
fn connect() {
// ...
}
}
mod network {
fn connect() {
// ...
}
}
mod client {
fn connect() {
// ...
}
}
fn main() {}
Модули
Можем да дефинираме подмодули и в отделни файлове
communicator
├── Cargo.toml
└── src
└── client.rs
└── lib.rs
└── network.rs
Модули
Можем да дефинираме подмодули и в отделни файлове
// src/lib.rs
mod network;
mod client;
// src/network.rs
fn connect() {
// ...
}
fn connect() {
// ...
}
fn main() {}
// src/client.rs
fn connect() {
// ...
}
fn connect() {
// ...
}
fn main() {}Модули
Можем да дефинираме подмодули и в отделни файлове
// src/lib.rs
mod network;
mod client;
// src/network.rs
fn connect() {
// ...
}
fn connect() {
// ...
}
fn main() {}
// src/client.rs
fn connect() {
// ...
}
fn connect() {
// ...
}
fn main() {}- декларираме подмодулите с
mod MOD_NAME; - компилатора търси файл
./MOD_NAME.rsили./MOD_NAME/mod.rs
Модули
Можем да имаме няколко нива на подмодули
// src/lib.rs
mod network {
fn connect() {
// ...
}
mod client {
fn connect() {
// ...
}
}
}
mod network {
fn connect() {
// ...
}
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 connect() {
// ...
}
// src/network/client.rs
fn connect() {
// ...
}
fn connect() {
// ...
}
fn main() {}
Достъп
В модул имаме директен достъп до всичко останало дефинирано в модула
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();
}
}
Достъп
Ако искаме да използваме нещо извън модула трябва да използваме пълното име
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() {
crate::client::connect();
}
}
- пълното име започва с име на crate-а или ключовата дума
crateако е дефинирано в нашия проект
Достъп
Ако искаме да използваме нещо извън модула трябва да използваме пълното име
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() {
crate::client::connect();
}
}
- пълното име започва с име на crate-а или ключовата дума
crateако е дефинирано в нашия проект - след това следва пътя до item-а
Достъп
Ако искаме да използваме нещо извън модула трябва да използваме пълното име
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() {
crate::client::connect();
}
}
- пълното име започва с име на crate-а или ключовата дума
crateако е дефинирано в нашия проект - след това следва пътя до item-а
crate::client::connectstd::vec::Vec
Достъп
Ако искаме да използваме нещо извън модула трябва да използваме пълното име..
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() {
crate::client::connect();
}
}
error[E0603]: function `connect` is private --> src/bin/main_45cfa89b529115e6bc0921c5bdec3a299e3e5247.rs:7:24 | 7 | crate::client::connect(); | ^^^^^^^ private function | note: the function `connect` is defined here --> src/bin/main_45cfa89b529115e6bc0921c5bdec3a299e3e5247.rs:2:5 | 2 | fn connect() { /* ... */ } | ^^^^^^^^^^^^
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() {
crate::client::connect();
}
}
fn main() {}
Достъп
… и освен това то трябва да е публично достъпно (keyword pub)
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() {}
Достъп
Можем да използваме use за да импортираме имена от друг модул
mod client {
pub 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 {
pub 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 {
pub 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модули)
Достъп
Ако искаме да импортираме неща от подмодул, може да използваме use self::... или use super::... за релативен път
mod network {
mod client {
// еквивалентно на use crate::network::init;
use super::init;
pub fn connect() { /* ... */ }
}
// еквивалентно на use crate::network::client::connect;
use self::client::connect;
fn init() {
connect();
}
}
#![allow(unused_imports)]
mod network {
mod client {
// еквивалентно на use crate::network::init;
use super::init;
pub fn connect() { /* ... */ }
}
// еквивалентно на use crate::network::client::connect;
use self::client::connect;
fn init() {
connect();
}
}
fn main() {}
Достъп: public и private
Достъп: public и private
- по подразбиране всичко е private
Достъп: public и private
- по подразбиране всичко е private
- за да се направи нещо достъпно извън модула, в който е дефинирано, се използва ключовата дума
pub
Достъп: public и private
- по подразбиране всичко е private
- за да се направи нещо достъпно извън модула, в който е дефинирано, се използва ключовата дума
pub - винаги има достъп до нещата, които са дефинирани в текущия модул, или по-нагоре в йерархията
Достъп: public и private
Нека да пуснем следния код
mod product {
pub struct User {
username: String,
email: String,
}
}
use self::product::User;
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
};
}
Достъп: public и private
Резултата
mod product {
pub struct User {
username: String,
email: String,
}
}
use self::product::User;
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
};
}
error[E0451]: field `username` of struct `product::User` is private --> src/bin/main_c0fba21675df6ceed4f332d59bc57cc61d74014d.rs:12:9 | 12 | username: String::from("Иванчо"), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private field error[E0451]: field `email` of struct `product::User` is private --> src/bin/main_c0fba21675df6ceed4f332d59bc57cc61d74014d.rs:13:9 | 13 | email: String::from("ivan40@abv.bg"), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private field
mod product {
pub struct User {
username: String,
email: String,
}
}
use self::product::User;
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
};
}
Достъп: public и private
Както казахме, по подразбиране всичко е private за външни модули, включително и полета на структурата.
Затова трябва да ги отбележим с pub.
mod product {
pub struct User {
pub username: String,
pub email: String,
}
}
use self::product::User;
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
};
}
mod product {
pub struct User {
pub username: String,
pub email: String,
}
}
use self::product::User;
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
};
}
Достъп: public и private
Без проблем може да достъпим private полета от същия модул в който е дефинирана структурата
mod product {
pub struct User {
username: String,
email: String,
}
pub fn new(username: String, email: String) -> User {
User { username, email }
}
}
fn main() {
let user = product::new(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
}
mod product {
pub struct User {
username: String,
email: String,
}
pub fn new(username: String, email: String) -> User {
User { username, email }
}
}
fn main() {
let user = product::new(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
}
Достъп: public и private
Както и без проблем може да достъпим private полета от подмодул
mod product {
pub struct User {
username: String,
email: String,
}
pub mod init_user {
use super::User;
pub fn new(username: String, email: String) -> User {
User { username, email }
}
}
}
fn main() {
let user = product::init_user::new(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
}
mod product {
pub struct User {
username: String,
email: String,
}
pub mod init_user {
use super::User;
pub fn new(username: String, email: String) -> User {
User { username, email }
}
}
}
fn main() {
let user = product::init_user::new(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
}
Достъп: public и private
Но ако модулите са съседни не можем
mod product {
mod dto {
pub struct User {
username: String,
email: String,
}
}
pub mod init_user {
use super::dto::User;
pub fn new(username: String, email: String) -> User {
User { username, email }
}
}
}
error[E0451]: field `username` of struct `product::dto::User` is private --> src/bin/main_6b1a305aea173c6966b97719e25b5ec58a4f6555.rs:13:20 | 13 | User { username, email } | ^^^^^^^^ private field error[E0451]: field `email` of struct `product::dto::User` is private --> src/bin/main_6b1a305aea173c6966b97719e25b5ec58a4f6555.rs:13:30 | 13 | User { username, email } | ^^^^^ private field
mod product {
mod dto {
pub struct User {
username: String,
email: String,
}
}
pub mod init_user {
use super::dto::User;
pub fn new(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]: expected function, tuple struct or tuple variant, found struct `UserId` --> src/bin/main_4ab3111369e2922d14fb54434dca1a25870e2bd1.rs:8:14 | 8 | let id = UserId(123); | ^^^^^^ constructor is not visible here due to private fields
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);
}
Пакети
Ще си направим игра за отгатване на число
$ cargo new number_guessing_game --bin
Пакети
- трябва ни генератор на случайни числа
Пакети
- трябва ни генератор на случайни числа
- в стандартната библиотека няма такъв
Пакети
- трябва ни генератор на случайни числа
- в стандартната библиотека няма такъв
- може да потърсим в https://crates.io/
Пакети
- трябва ни генератор на случайни числа
- в стандартната библиотека няма такъв
- може да потърсим в https://crates.io/
- https://crates.io/crates/rand
Cargo.toml
Трябва да си добавим пакета като зависомист на проекта ни
[package]
name = "number_guessing_game"
version = "0.1.0"
authors = ["..."]
edition = "2018"
[dependencies]
Cargo.toml
Трябва да си добавим пакета като зависомист на проекта ни
[package]
name = "number_guessing_game"
version = "0.1.0"
authors = ["..."]
edition = "2018"
[dependencies]
rand = "0.7.2"
Използване
След като се добави библиотека в [dependencies], може да се използва както всеки останал модул
use rand::*;
// ...
Документация
- https://docs.rs/ - документация за всички пакети от crates.io
Документация
- https://docs.rs/ - документация за всички пакети от crates.io
- https://docs.rs/rand/
Имплементация
Live demo
Имплементация
Код от демото
use rand::prelude::*;
use std::io::{self, Write};
fn main() {
// Generate a random number between 0 and 10
let secret = rand::thread_rng().gen_range(0, 10_u32);
let stdin = io::stdin();
let tries = 5;
println!("You have {} tries to guess the number. Good luck!", tries);
for _ in 0..tries {
// Note that stdout is frequently line-buffered by default so it may be necessary
// to use io::stdout().flush() to ensure the output is emitted immediately.
print!("Your guess: ");
let _ = io::stdout().flush();
let mut line = String::new();
let _ = stdin.read_line(&mut line);
// No error handling - panic if parsing fails
let guess: u32 =
line
.trim()
.parse()
.unwrap();
if secret < guess {
println!("I am less than that");
} else if secret > guess {
println!("I am greater than that");
} else {
println!("Congratulations, you won!");
return;
}
}
println!("The number was {}", secret);
}