Структури, модули, външни пакети
11 октомври 2018
Административни неща
Административни неща
- Инсталирайте си Rust: https://2018.fmi.rust-lang.bg/topics/2
Административни неща
- Инсталирайте си Rust: https://2018.fmi.rust-lang.bg/topics/2
- Елате в Discord канала: https://discord.gg/FCTNfbZ
Административни неща
- Инсталирайте си Rust: https://2018.fmi.rust-lang.bg/topics/2
- Елате в Discord канала: https://discord.gg/FCTNfbZ
- Регистрирайте се в https://fmi.rust-lang.bg!
Съдържание
Съдържание
- преговор с допълнение
Съдържание
- преговор с допълнение
- структури
Съдържание
- преговор с допълнение
- структури
- методи
Съдържание
- преговор с допълнение
- структури
- методи
- модули
Съдържание
- преговор с допълнение
- структури
- методи
- модули
- използване на пакети от crates.io
Преговор
Преговор
- Преместване и копиране. Move semantics
Преговор
- Преместване и копиране. Move semantics
- Собственост и заемане (Ownership & borrowing)
Преговор
- Преместване и копиране. Move semantics
- Собственост и заемане (Ownership & borrowing)
- Псевдоними (
&T
и&mut T
)
Преговор
- Преместване и копиране. Move semantics
- Собственост и заемане (Ownership & borrowing)
- Псевдоними (
&T
и&mut T
) - Borrow checker
Преговор
Типа String
let mut s = String::from("hello");
s.push_str(", world");
println!("{}", s);
hello, world
Преговор
Типа &str (string slice)
let s = String::from("hello, world");
let r1 = &s[..];
let r2 = &r1[1..4];
println!("{}", r2);
ell
Преговор
Tипа Vec
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);
println!("{:?}", v);
[1, 2, 3]
Преговор
.. и макрото vec!
let v = vec![1, 2, 3];
println!("{:?}", v);
[1, 2, 3]
Неща, за които не ни стигна времето
Типа &[T]
Неща, за които не ни стигна времето
Типа &[T]
- резен от масив
Неща, за които не ни стигна времето
Типа &[T]
- резен от масив
- аналогично на &str
Неща, за които не ни стигна времето
Типа &[T]
- резен от масив
- аналогично на &str
- репрезентиран като
(ptr, len)
&[T]
Slice literal
let slice = &[1, 2, 3];
println!("{:?}", slice);
[1, 2, 3]
&[T]
Array slice
let arr = [1, 2, 3];
let slice = &arr[..];
println!("{:?}", slice);
[1, 2, 3]
&[T]
Vector slice
let v = vec![1, 2, 3];
let slice = &v[..];
println!("{:?}", slice);
[1, 2, 3]
Бонус синтаксис
Бонус синтаксис
Създаване на масиви с еднакви елементи
let zeroed = [0, 0, 0, 0, 0, 0, 0, 0];
println!("{:?}", zeroed);
[0, 0, 0, 0, 0, 0, 0, 0]
Бонус синтаксис
Създаване на масиви с еднакви елементи
let zeroed = [0; 8];
println!("{:?}", zeroed);
[0, 0, 0, 0, 0, 0, 0, 0]
Бонус синтаксис
Създаване на масиви с еднакви елементи
let zeroed = [0; 8];
println!("{:?}", zeroed);
[0, 0, 0, 0, 0, 0, 0, 0]
Синтаксисът е [element; count]
Бонус синтаксис
Създаване на вектори с еднакви елементи
let zeroed = vec![0; 8];
println!("{:?}", zeroed);
[0, 0, 0, 0, 0, 0, 0, 0]
Структури
Структури
Синтаксис
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 = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
sign_in_count: 10,
};
println!("{}, {}", user.username, user.email);
Иванчо, ivan40@abv.bg
Структури
Достъп до полета
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
Структури
Достъп до полета
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
Полетата се доспъпват по същия начин и през референция
Структури
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 { ... }
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,
}
}
}
struct
блока съдържа само полетата на структурата
Методи и асоциирани функции
struct User { ... }
impl User {
fn new(username: String, email: String) -> User {
User {
username: username,
email: email,
sign_in_count: 0,
}
}
}
struct
блока съдържа само полетата на структурата- методи и функции се добавят в отделен
impl
блок
Методи и асоциирани функции
let user = User::new(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
Методи и асоциирани функции
let user = User::new(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
- функцията
new
е префиксната с името на структурата (User
) и оператора::
Методи и асоциирани функции
Конструктури и деструктури
Методи и асоциирани функции
Конструктури и деструктури
- в Rust няма конструктори
Методи и асоциирани функции
Конструктури и деструктури
- в Rust няма конструктори
- вместо това се използват асоциирани функции
Методи и асоциирани функции
Конструктури и деструктури
- в Rust няма конструктори
- вместо това се използват асоциирани функции
- често използвани имена са
new
from_*
with_*
Методи и асоциирани функции
Конструктури и деструктури
- в Rust няма конструктори
- вместо това се използват асоциирани функции
- често използвани имена са
new
from_*
with_*
- в Rust има деструктори, но за тях ще говорим по-късно
Методи и асоциирани функции
Още един пример
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
}
}
Методи и асоциирани функции
Кратък синтаксис за създаване на структури
let width = 2.0;
let height = 3.0;
let rect = Rectangle {
width: width,
height: height,
};
let width = 2.0;
let height = 3.0;
let rect = Rectangle {
width,
height,
};
Методи и асоциирани функции
Типа Self
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
}
Методи и асоциирани функции
Типа Self
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
}
- достъпен само в
impl
блок
Методи и асоциирани функции
Типа Self
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn new(width: f64, height: f64) -> Self {
Self { width, height }
}
}
- достъпен само в
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
}
}
- функция, която приема като първи аргумент
self
,&self
,&mut self
(method receiver)
Методи и асоциирани функции
Методи
struct Rectangle { width: f64, height: f64 }
impl Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
- функция, която приема като първи аргумент
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
}
}
- функция, която приема като първи аргумент
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
}
}
- функция, която приема като първи аргумент
self
,&self
,&mut self
(method receiver) self
<=>self: Self
&self
<=>self: &Self
&mut self
<=>self: &mut Self
Методи и асоциирани функции
Методи
Методите могат да се използват като най-обикновена функция
let rect = Rectangle::new(2.0, 3.0);
let area = Rectangle::area(&rect);
println!("{}", area);
6
Методи и асоциирани функции
Методи
Но могат и да се извикват със синтаксиса за методи
let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();
println!("{}", area);
6
Методи и асоциирани функции
Методи
Но могат и да се извикват със синтаксиса за методи
let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();
println!("{}", area);
6
- както полетата, методите се достъпват с
.
Методи и асоциирани функции
Методи
Но могат и да се извикват със синтаксиса за методи
let rect = Rectangle::new(2.0, 3.0);
let area = rect.area();
println!("{}", area);
6
- както полетата, методите се достъпват с
.
- компилатора автоматично добавя
*
,&
или&mut
, така че аргумента да съвпадне с method receiver-а
Tuple structs
Именувани кортежи
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
Празни структури
struct Electron {}
struct Proton;
let x = Electron {};
let y = Proton;
Модули
cargo new communicator --lib
communicator
├── Cargo.toml
└── src
└── lib.rs
Модули
Модули в същия файл
// src/lib.rs
mod network {
fn connect() {
// ...
}
}
mod client {
fn connect() {
// ...
}
}
Модули
Модули в отделни файлове
// src/lib.rs
mod network;
mod client;
// src/network.rs
fn connect() {
// ...
}
// src/client.rs
fn connect() {
// ...
}
Модули
Модули в отделни файлове
communicator
├── Cargo.toml
└── src
└── client.rs
└── lib.rs
└── network.rs
Подмодули
Подмодули в същия файл
// src/lib.rs
mod network {
fn connect() {
// ...
}
mod client {
fn connect() {
// ...
}
}
}
Подмодули
Подмодули в отделни файлове
// src/lib.rs
mod network;
// src/network/mod.rs
mod client;
fn connect() {
// ...
}
// src/network/client.rs
fn connect() {
// ...
}
Подмодули
Подмодули в отделни файлове
communicator
├── Cargo.toml
└── src
└── lib.rs
└── network
└── client.rs
└── mod.rs
Подмодули
Подмодули в отделни файлове
communicator
├── Cargo.toml
└── src
└── lib.rs
└── network
└── client.rs
└── mod.rs
Компилаторът търси за файловете MOD_NAME.rs
или MOD_NAME/mod.rs
Достъп
В модул имаме директен достъп до всичко останало дефинирано в модула
mod client {
fn connect() { /* ... */ }
fn init() {
// client::connect();
connect();
}
}
Достъп
Ако искаме да използваме нещо извън модула трябва да използваме пълното име
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() {
::client::connect();
}
}
Достъп
Ако искаме да използваме нещо извън модула трябва да използваме пълното име..
mod client {
fn connect() { /* ... */ }
}
mod network {
fn init() {
::client::connect();
}
}
error[E0603]: function `connect` is private --> /src/main_32.rs:8:9 | 8 | ::client::connect(); | ^^^^^^^^^^^^^^^^^
Достъп
.. и освен това то трябва да е публично достъпно (keyword pub
)
mod client {
pub fn connect() { /* ... */ }
}
mod network {
fn init() {
::client::connect();
}
}
Достъп
Можем да използваме use
за да импортираме имена от друг модул
mod client {
pub fn connect() { /* ... */ }
}
mod network {
use client::connect;
fn init() {
connect();
}
}
Достъп
Ако искаме да импортираме неща от подмодул, може да използваме use self::...
за релативен път
mod network {
mod client {
pub fn connect() { /* ... */ }
}
// еквивалентно на use network::client::connect;
use self::client::connect;
fn init() {
connect();
}
}
Достъп: public и private
Достъп: public и private
- по подразбиране всичко е private
Достъп: public и private
- по подразбиране всичко е private
- за да се направи нещо достъпно извън модула, в който е дефинирано, се използва
pub
Достъп: public и private
- по подразбиране всичко е private
- за да се направи нещо достъпно извън модула, в който е дефинирано, се използва
pub
- винаги има достъп до нещата, които са дефинирани в текущия модул, или по-нагоре в йерархията
Достъп: public и private
mod user {
pub struct User {
username: String,
email: String,
}
}
use self::user::User;
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
};
}
Достъп: public и private
mod user {
pub struct User {
username: String,
email: String,
}
}
use self::user::User;
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
};
}
error[E0451]: field `username` of struct `user::User` is private --> /src/main_36.rs:14:9 | 14 | username: String::from("Иванчо"), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `username` is private error[E0451]: field `email` of struct `user::User` is private --> /src/main_36.rs:15:9 | 15 | email: String::from("ivan40@abv.bg"), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `email` is private
Достъп: public и private
mod user {
pub struct User {
pub username: String,
pub email: String,
}
}
use self::user::User;
fn main() {
let user = User {
username: String::from("Иванчо"),
email: String::from("ivan40@abv.bg"),
};
}
Достъп: public и private
mod user {
pub struct User {
username: String,
email: String,
}
pub fn new(username: String, email: String) -> User {
User { username, email }
}
}
fn main() {
let user = user::new(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
}
Достъп: public и private
mod user {
pub struct User {
username: String,
email: String,
}
pub mod init {
use super::User;
pub fn new(username: String, email: String) -> User {
User { username, email }
}
}
}
fn main() {
let user = user::init::new(
String::from("Иванчо"),
String::from("ivan40@abv.bg"),
);
}
Достъп: public и private
mod user {
mod user {
pub struct User {
username: String,
email: String,
}
}
pub mod init {
use super::user::User;
pub fn new(username: String, email: String) -> User {
User { username, email }
}
}
}
error[E0451]: field `username` of struct `user::user::User` is private --> /src/main_40.rs:15:20 | 15 | User { username, email } | ^^^^^^^^ field `username` is private error[E0451]: field `email` of struct `user::user::User` is private --> /src/main_40.rs:15:30 | 15 | User { username, email } | ^^^^^ field `email` is private
Пакети
Ще си направим игра за отгатване на число
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 = ["Nikola Stoyanov <ns.barzakov@gmail.com>"]
[dependencies]
Cargo.toml
[package]
name = "number_guessing_game"
version = "0.1.0"
authors = ["Nikola Stoyanov <ns.barzakov@gmail.com>"]
[dependencies]
rand = "0.5.5"
Използване
extern crate rand;
// ...
Използване
extern crate rand;
// ...
cargo build
Документация
- https://docs.rs/ - документация за всички пакети от crates.io
Документация
- https://docs.rs/ - документация за всички пакети от crates.io
- https://docs.rs/rand/
Имплементация
Live demo