Development

Find out how to create and organize your content quickly and intuitively.

  • Git

    Using Git repository

  • Rust

    Rust language notes

Subsections of Development

Git

Configuring Git

git config --global user.name "spider_net" # username init, seen in commits
git config --global user.email "test@gmail.com" # Init of user e-mail

SSH ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ с GitHub ΠΈ Gitlab

Для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΎΠ΄Π½ΠΎΠΉ систСмы с Ρ‚Π΅ΠΌ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠΌ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠ΅ΠΌ ΠΏΠΎ SSH Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΊΠ»ΡŽΡ‡ΠΈ SSH ΠΏΠΎΠ΄ ΠΎΠ±Π°, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΡ€ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ Π² Ρ„Π°ΠΉΠ»Π΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ ΠΏΡ€ΠΎΡ„ΠΈΠ»ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ:

Host github.com
  IdentityFile ~/.ssh/id_rsa
  IdentitiesOnly yes

Host gitlab.com
  IdentityFile ~/.ssh/id_ecdsa

Для ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ работоспособности ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ssh Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ:

ssh -vvvv git@github.com

Для избСТания ошибок слСдуСт:

  • Π’ ΠΈΠΌΠ΅Π½ΠΈ ΠΊΠ»ΡŽΡ‡Π° Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π·Π½Π°ΠΊ Ρ‚ΠΈΡ€Π΅ -
  • Π‘Π½Π°Ρ‡Π°Π»Π° ΠΊΠ»ΠΎΠ½ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΡƒΠ΄Π°Π»Ρ‘Π½Π½Ρ‹ΠΉ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ git clone, Π΄Π°Π»Π΅Π΅ локально Π΅Π³ΠΎ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΈ ΡΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ git push origin main

Cloning Repository

git clone https://github.com/drupal/drupal.git drupal7

Initialising Local & Remote Repo

git init # local repo init

git status # check status

git branch -m master main # change master branch to main, for GitLab

git add * # add all files to repo, .gitignore file lets you hide junk files, password files from syncing

git commit -m "Hello world"

git config --global user.email "Ivan@example.com"
git config --global user.name "Ivan the Terrible"

git log

git remote add origin git@gitlab.com:<name of account>/<project name>.git

git push origin main

Cloning Remote Repo on Amazon

Certificate file needed in .ssh folder. Also a config file .ssh/config is needed:

Host git-codecommit.us-east-1.amazonaws.com
   User Your-SSH-Key-ID, such as APKAEIBAERJR2EXAMPLE
   IdentityFile Your-Private-Key-File, such as ~/.ssh/codecommit_rsa or     ~/.ssh/id_rsa

Git commands to clone repo:

git clone ssh://<SSHKEY-ID>@git-codecommit.<REGION>.amazonaws.com/v1/repos/<REPO-NAME>

# Example:

git clone ssh://ABCDOIJKHJGYTHJG7@git-codecommit.eu-central-1.amazonaws.com/v1/repos/myrepo

Branching

Create new branch: git branch new-branch Pointer does not automatically switch to new branch, it is left on main branch, so you need to switch manually: git checkout new-branch

Merging Branches

  • Switch to branch for merging
  • Merge
  • Check pointers point to one place OR merge the other branch with the current one
git commit
git checkout main
git commit
git merge new-branch

Change of branches to make it look as if the functionality was developed step-by-step, not in parallel.

git rebase master
git checkout master
git rebase bugFix

Pointer

HEAD is the pointer to current project state. By default HEAD points to current branch. You can go back by commits or by direct commit hash: git checkout C1

You can use syntax “^K” for going up 1 level (where K is the route number to choose if there are more than 1 parent. By default, K=1) and “~N” for N steps up:

git checkout master^
# OR
git checkout bugFix^^
# OR
git checkout bugFix~2
# same route on schema from picture
# or build a sequence
git checkout bugFix^~1

Chaning main branch to several commits backwards:

git branch -f master HEAD~3
# -f means force - direct remap of branch for commit

Undo Actions

For 1-person local repo do reset. For multi-person remote repo, do revert.

git reset HEAD~1
# OR
git revert HEAD

reset reset revert revert In c2’ state are the changes, which cancel state C2

Moving commits

Chosen commits are moved upon current commit using cherry-pick command. Used when it is known what specific commits to move: git cherry-pick C2 C4 git rebase -i HEAD~4 --aboveAll

Small commit modifications

You can modify a commit, dividing it into two with same parent: git commit --amend

Tagging commits

Marking milestones is done with tags. They block the commit from changes, moving etc.:

git tag v1 <hash> # if hash is not provided, then current commit is tagged

Tags serve as anchors in tree of commits. To define your position against the nearest anchor, use command:

git describe <ref> # if <ref> is not provided, current commit will be described

Naming

Remote branches have a naming convention: <remote name>/<branch name>

Main remote i called origin. So master branch is origin/main. When doing commit in local branch, the system is put into detached HEAD mode:

git checkout origin/master
git commit

Fetch data from remote repository

When data is downloaded from remote repo, the origin/main branch is updated to reflect the new commits: git fetch

Only commits non-present locally are downloaded. No local state of files is changed after download. The local main status is unchanged. To change, a merge must be done: git fetch + git merge = git pull git pull

Publishing local repository to remote

Publishing syncs commits at remote repo and local repo (main and origin/main point to the same commit): git push

If the remote repo has changed by someone by the time you need to push there, it means that your feature is based on an old commit. So Git will not let you push. Before push, a fetch must be made to sync the changes, than a rebase or merge to update the main branch, and then a push:

git fetch + git rebase origin/main + git push OR git fetch + git merge origin/main + git push = git pull –rebase git pull --rebase

Changing main and origin/main

You can change that another branch will be main for the remote repo: `git checkout -b side origin/main

Push arguments

You can specify what branch to push: git push origin main

origin = remote repo, main = branch to take commit from.

It does not matter where the HEAD is at this moment. You can specify where to push commits using git push origin <source>:<destination> notation: git push origin side^2:master

If push is made to a non-existent branch on remote repo, Git will create this branch: git push origin main:newBranch

Fetch arguments

Same as push, but the other wat around. Go to foo branch on remote repo, download commits from there to local branch origin/foo: git fetch origin foo

Rust

Articles in Section

АргумСнты Π·Π°/ΠΏΡ€ΠΎΡ‚ΠΈΠ² Rust

ΠŸΠ»ΡŽΡΡ‹ Rust:

  • Memory safety, высокая ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ +самыС быстрыС Π² ΠΌΠΈΡ€Π΅ Π²Π΅Π±-Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠΈ https://www.techempower.com/benchmarks/#hw=ph&test=fortune§ion=data-r22
  • Высокая ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ вычислСний для ML, Python ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΏΠΎΠ΄ ΠΊΠ°ΠΏΠΎΡ‚ΠΎΠΌ Π½Π° Polars Π²Π·Π°ΠΌΠ΅Π½ Pandas - https://rongxin.me/substitute-pandas-with-polars-a-dataframe-module-rewritten-in-rust
  • Π»ΡŽΠ±ΠΈΠΌΡ‹ΠΉ язык StackOverflow ΡƒΠΆΠ΅ 8+ Π»Π΅Ρ‚ https://survey.stackoverflow.co/2024/technology/#admired-and-desired
  • Π―Π΄Ρ€ΠΎ Linux, ядро Android, ядро Windows, ядро ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠ² ΠΏΠ΅Ρ€Π΅Π΅Π·ΠΆΠ°Π΅Ρ‚ с Golang
  • ΠŸΡ€ΠΎΠ΅ΠΊΡ‚ пСрСписывания всСх Π³Π»Π°Π²Π½Ρ‹Ρ… систСмных ΡƒΡ‚ΠΈΠ»ΠΈΡ‚ Linux Π½Π° Rust - https://github.com/TaKO8Ki/awesome-alternatives-in-rust
  • Fearless Concurrency
  • Π”ΠΈΠ°Π»ΠΎΠ³ с компилятором
  • ΠŸΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ максимально Ρ‡Ρ‘Ρ‚ΠΊΠΎ
  • Π½Π΅Ρ‚ void / null https://www.youtube.com/watch?v=ybrQvs4x0Ps
  • мощная типизация
  • traits вмСсто классов ΠΈ наслСдования
  • Π•Π΄ΠΈΠ½Ρ‹ΠΉ сборщик Cargo
  • На Π²Ρ‹Ρ…ΠΎΠ΄Π΅ Π΅Π΄ΠΈΠ½Ρ‹ΠΉ Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊ ΠΊΠ°ΠΊ Π² Golang
  • Нативная ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° WebAssembly (Π·Π° счёт отсутствия сборщика мусора), ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ язык
  • Rust Π³Π»Π°Π²Π½Ρ‹ΠΉ язык Π½Π°Π΄Ρ‘ΠΆΠ½ΠΎΠΉ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ финансовых инструмСнтов для Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΉ Blockchain

ΠœΠΈΠ½ΡƒΡΡ‹:

  • Π•Π³ΠΎ слоТно ΡƒΡ‡ΠΈΡ‚ΡŒ, ΠΌΠ½ΠΎΠ³ΠΎ синтаксиса
  • ΠŸΠ΅Ρ€Π΅ΡΡ‚Ρ€ΠΎΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠ·Π³ΠΎΠ²: Π΄ΡƒΠ°Π»ΠΈΠ·ΠΌ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° (enums Result), ΠΌΠ΅Ρ‚ΠΊΠΈ lifecycle, traits
  • Π―Π·Ρ‹ΠΊ ΠΌΠΎΠ»ΠΎΠ΄ΠΎΠΉ, экосистСма Π±Π΅Π΄Π½Π΅Π΅ Ρ‡Π΅ΠΌ Ρƒ Python, Ρ‚Π΅ΠΌ Π±ΠΎΠ»Π΅Π΅ Ρ‡Π΅ΠΌ Ρƒ C++, сообщСство мСньшС

БравнСния

Golang, Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΉ-ΠΏΠ»ΠΎΡ…ΠΎΠΉ-Π·Π»ΠΎΠΉ: https://habr.com/ru/companies/vk/articles/353790/

ВидСокурсы

Π—Π°Π΄Π°Ρ‡ΠΈ ΠΏΠΎ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡŽ

Rust Tools

External links:

rustup component add rustfmt 
rustup component add rust-src
  • Install Bacon (formerly Cargo-watch) to rerun code upon save:
cargo install --locked bacon
#cargo install cargo-watch
git clone https://github.com/AstroNvim/AstroNvim ~/.config/nvim
nvim +PackerSync

# After install use commands:
:LspInstall rust -> rust-analyzer
:TSInstall rust
  • Neovide GUI upgrade on Astro Vim
git clone https://github.com/neovide/neovide
cd neovide
cargo build --release
  • EVCXR or iRUST REPL
cargo install evcxr_repl
cargo install irust
cargo install --locked bacon
bacon test # run from project folder 

VSCode Extensions for Rust

  • CodeLLDB
  • Dependi (Π±Ρ‹Π²Ρˆ crates) - сообщаСт, Ссли ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ устарСли

VSCode Settings

(For CodeLLDB) Allow breakpoints everywhere: "debug.allowBreakpointsEverywhere": true cargo check: ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ check Π½Π° clippy: "rust-analyzer.check.command": "clippy"

Rust Prelude

Rust has a Prelude - a set of libraries included in every project. See current libs included in Prelude

Allow Unused

Turn off noise about unused objects while learning with a crate attribute:

#![allow(unused)] // silence unused warnings while learning
fn main() {}

User input

std::io::stdin library is used to get user input from standard input stream. Not included in Prelude:

use std:io

let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("Failed to load");

.expect handles Err variant of read_line function, crashing the program with the defined error message.

Subsections of Rust

Cargo

Use Cargo for managing projects.

cargo new test_project // create project with binary file src/main.rs
// OR
cargo new test_project --lib // create project with library file src/lib.rs 

cd test_project

Source code is in src folder.

cargo build # build project for debug, do not run
cargo run # build & run project
cargo check # fast compiling
cargo build --release # slow build with optimizations for speed of release version

Documentation of methods & traits used in code can be compiled an opened in browser with Cargo command:

cargo doc --open

Cargo Examples

Create “examples” folder beside the “src” folder. Create a file named, for example, “variables.rs” and place some test code in the folder. Then in the project root folder run:

cargo run --example variables

(new) Bacon - ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΉ пСрСзапуск компиляции

This will compile+build the code in examples folder, file “variables.rs”. Very convenient to try test different stuff. For live development do:

bacon run -- -q # ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚
bacon run -- -q --example <Ρ„Π°ΠΉΠ»> # ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» Π² ΠΏΠ°ΠΏΠΊΠ΅ examples

-q - ΡƒΠ±Ρ€Π°Ρ‚ΡŒ Π²Ρ‹Π²ΠΎΠ΄ Π΄Π΅Ρ‚Π°Π»Π΅ΠΉ компиляции

(old) Cargo Watch - ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΉ пСрСзапуск компиляции

This will compile+build the code in examples folder, file “variables.rs”. Very convenient to try test different stuff. For live development do:

cargo watch -q -c -x 'run -q --example variables'

-x - rerun upon code change -c - clear terminal each time -q - quiet mode β—ΠŸΡ€ΠΎΠ΅ΠΊΡ‚ cargo watch Π·Π°ΠΌΠΎΡ€ΠΎΠΆΠ΅Π½, Π±ΠΎΠ»Π΅Π΅ Π½Π΅ развиваСтся.

Panic Response

Π’ ΠΎΡ‚Π²Π΅Ρ‚ Π½Π° ΠΏΠ°Π½ΠΈΠΊΡƒ, ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Ρ€Π°Π·ΠΌΠ°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ стСк (unwinding) - ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ ΠΏΠΎ стСку ΠΈ Π²Ρ‹Ρ‡ΠΈΡ‰Π°Π΅Ρ‚ Π΄Π°Π½Π½Ρ‹Π΅ всСх Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ. Для ΡƒΠΌΠ΅Π½ΡŒΡˆΠ΅Π½ΠΈΡ Ρ€Π°Π·ΠΌΠ΅Ρ€Π° ΠΌΠΎΠΆΠ½ΠΎ просто ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Π±Π΅Π· очистки - abort. Для этого Π² Ρ„Π°ΠΉΠ»Π΅ Cargo.toml Π½Π°Π΄ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² Ρ€Π°Π·Π΄Π΅Π»Ρ‹ [profile]:

[profile.release]
panic = 'abort'

Cargo Clippy linter

Example of Clippy config:

cargo clippy --fix -- \
-W clippy::pedantic \
-W clippy::nursery \
-W clippy::unwrap_used \
-W clippy::expect_used

Clippy has a markdown book:

cargo install mdbook
# Run from top level of your rust-clippy directory:
mdbook serve book --open
# Goto http://localhost:3000 to see the book

Important Cargo libs

  • Tokio - async runtime
  • Eyre & color-eyre - type signatures, error report handling
  • Tracing - collect diagnostic info
  • Reqwest - HTTP requests library, async
  • Rayon - data parallelism library, without data races
  • Clap - commandline passing library
  • SQLX - compile-checked SQL, async
  • Chrono - time/date library
  • EGUI - web-gui @60FPS, runs in Webassembly
  • Yew.rs - web-library like React.js

Subsections of Cargo

Cargo Offline

Cargo OFFLINE

Для создания локального сСрвСра ΠΌΠΎΠΆΠ½ΠΎ ΡΠΊΠ°Ρ‡Π°Ρ‚ΡŒ всС ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ Cargo с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Panamax.

cargo install --locked panamax
panamax init ~/test/my-mirror

НуТно Π·Π°ΠΉΡ‚ΠΈ Π² ΠΏΠ°ΠΏΠΊΡƒ my-mirror, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ настройки Π² Ρ„Π°ΠΉΠ»Π΅ mirror.toml. И Π΄Π°Π»Π΅Π΅ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΡΠΈΠ½Ρ…Ρ€ΠΎΠ½ΠΈΠ·Π°Ρ†ΠΈΡŽ:

panamax sync ~/test/my-mirror

Π”Π°Π»Π΅Π΅, ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Ρ‚ΡŒ Π·Π΅Ρ€ΠΊΠ°Π»ΠΎ ΠΏΠΎ Π²Π΅Π± Ρ‡Π΅Ρ€Π΅Π· встроСнный сСрвСр (ΠΏΠΎ ΠΏΠΎΡ€Ρ‚Ρƒ 8080):

panamax serve ~/test/my-mirror

На индСкс страницС сСрвСра Π±ΡƒΠ΄Π΅Ρ‚ справка ΠΏΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡŽ Rust ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠ² ΠΊ Π·Π΅Ρ€ΠΊΠ°Π»Ρƒ. Π’ частности, посрСдством создания Ρ„Π°ΠΉΠ»Π° настроСк ~/.cargo/config :

[source.my-mirror]
registry = "http://panamax.local/crates.io-index"
[source.crates-io]
replace-with = "my-mirror"

Cargo Workspaces

Cargo Workspaces

ОбъСдинСниС ΠΊΠΎΠ΄Π° Π² 1 ΠΏΡ€ΠΎΠ΅ΠΊΡ‚. Π’ Cargo.toml Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ±ΡŠΡΠ²ΠΈΡ‚ΡŒ Π΅Π³ΠΎ структуру:

[package]
name = "ardan_workspace"
version = "0.1.0"
edition = "2021"

[dependencies]

[workspace]
members = [ 
  "session1/hello_world",
  "session1/variables",
]

ПослС этого ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ ΠΏΠΎΠ΄ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π² members, Ρ‡Π΅Ρ€Π΅Π· cargo new <ΠΏΠΎΠ΄Ρ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°>.

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Π² Workspace

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ вмСсто Π±ΠΈΠ½Π°Ρ€Π½ΠΈΠΊΠ° - `cargo new –lib examplelib

ΠŸΡ€ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ Π² Ρ„Π°ΠΉΠ»Π΅ cargo.toml Ρƒ Π±ΠΈΠ½Π°Ρ€Π½ΠΎΠΉ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π² workspace Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡ‚ΡŒ:

<..>

[dependencies]
examplelib = { path = "../examplelib"}

Π”Π°Π»Π΅Π΅, Π² ΠΊΠΎΠ΄ Π±ΠΈΠ½Π°Ρ€Π½ΠΎΠΉ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ· Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ:

use examplelib::function01; // фукнкция Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½ΠΎΠΉ (pub fn)

Libraries

Articles in Section

Library Unit-tests

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹:

pub fn greet_user(name: &str) -> String {
    format!("Hello {name}")
}

pub fn login(username: &str, password: &str) -> bool {
    username == "admin" && password == "P@ssw0rd"
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_greet_user() {
        assert_eq!("Hello Alex", greet_user("Alex"));
    }

    #[test]
    fn test_login() {
        assert!(login("admin", "P@ssw0rd"));
    }
}

Запуск тСстов - ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ cargo test

Subsections of Libraries

Anyhow Error Handler

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ошибками - https://docs.rs/anyhow/latest/anyhow/

  • Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π΅Π΄ΠΈΠ½Ρ‹ΠΉ Ρ‚ΠΈΠΏ Error для всСх ошибок;
  • ДобавляСт контСкст ΠΊ ошибкам;
  • ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° backtrace для debug;

Установка

cargo add anyhow

ИспользованиС

Anyhow создаёт алиас Π½Π°ΠΏΠΎΠ΄ΠΎΠ±ΠΈΠ΅ Result<T> = Result<T, Box<dyn Error>>, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠΊΡ€Ρ‹Ρ‚ΡŒ Ρ‚ΠΈΠΏ ошибок ΠΈ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π΅Π³ΠΎ ΡƒΠ½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½Ρ‹ΠΌ.

// ---- Π‘Π΅Π· Anyhow
fn string_error() -> Result<(), String> {
    Ok(())
}
fn io_error() -> Result<(), std::io::Error> {
    Ok(())
}
fn any_error() -> Result<(), Box<dyn Error>> {
    string_error()?;
    io_error()?;
    Ok(())
}
// ---- Π‘ Anyhow:
use anyhow::Result;

fn string_error() -> Result<()> {
    Ok(())
}
fn io_error() -> Result<()> {
    Ok(())
}
fn any_error() -> Result<()> {
    string_error()?;
    io_error()?;
    Ok(())
}

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π½Π΅ΡƒΠ΄Π°Ρ‡Π½ΠΎΠ³ΠΎ чтСния Ρ„Π°ΠΉΠ»Π°:

use anyhow::{Context, Result};

fn read_config_file(path: &str) -> Result<String> {
    std::fs::read_to_string(path).with_context(|| format!("Failed to read file {}", path))
}

fn main() -> Result<()> {
    let config_content = read_config_file("conf.txt")?;

    println!("Config content:\n{:?}", config_content);

    Ok(())
}
  • Result<T> становится алиасом ΠΊ Result<T, anyhow::Error>;
  • Context, with_context() позволяСт Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ подробности ΠΊ ошибкС, Π² случаС нСуспСха Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ чтСния read_to_string();
  • ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ ? выносит ΠΎΡˆΠΈΠ±ΠΊΡƒ Π²Π²Π΅Ρ€Ρ…, ΠΏΡ€ΠΈ этом Π°Π²Ρ‚ΠΎ-ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚ Π΅Ρ‘ Ρ‚ΠΈΠΏ Π² anyhow::Error.

Π—Π°ΠΌΠ΅Π½Π° Box<dyn> с контСкстом

Π’ΠΎΠ·ΡŒΠΌΡ‘ΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»Π° std::fs::read_to_string() (ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π½Π΅ΡƒΠ΄Π°Ρ‡Π½Ρ‹ΠΌ), Π΄Π°Π»Π΅Π΅ Π΄Π΅ΡˆΠΈΡ„Ρ€ΠΎΠ²ΠΊΠ° Π΅Π³ΠΎ ΠΊΠΎΠ½Ρ‚Π΅Π½Ρ‚Π° с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ base64 decode() (ΠΌΠΎΠΆΠ΅Ρ‚ Π½Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒΡΡ) Π² Ρ†Π΅ΠΏΠΎΡ‡ΠΊΡƒ Π±Π°ΠΉΡ‚, ΠΈΠ· ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ формируСтся строка String::from_utf8() (ΠΌΠΎΠΆΠ΅Ρ‚ Π½Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒΡΡ). ВсС эти Ρ‚Ρ€ΠΈ ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Ρ… ошибки ΠΈΠΌΠ΅ΡŽΡ‚ Ρ€Π°Π·Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ.

Один способ всС Ρ‚Ρ€ΠΈ ΠΈΡ… ΠΏΡ€ΠΈΠ½ΡΡ‚ΡŒ Π½Π° ΠΎΠ΄Π½Ρƒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, это с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Box<dyn std::error::Error>>, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ всС 3 ошибки ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡŽΡ‚ std::error::Error.

use base64::{self, engine, Engine};

fn decode() -> Result<(), Box<dyn std::error::Error>> {
    let input = std::fs::read_to_string("input")?;
    for line in input.lines() {
        let bytes = engine::general_purpose::STANDARD.decode(line)?;
        println!("{}", String::from_utf8(bytes)?);
    }
    Ok(())
}

ΠŸΠΎΠ΄Ρ…ΠΎΠ΄ Ρ€Π°Π±ΠΎΡ‡ΠΈΠΉ, Π½ΠΎ ΠΏΡ€ΠΈ срабатывании ΠΎΠ΄Π½ΠΎΠΉ ΠΈΠ· Ρ‚Ρ€Ρ‘Ρ… ошибок, ΡΡƒΠ΄ΠΈΡ‚ΡŒ ΠΎ происхоТдСнии ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ ΠΌΠΎΠΆΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ лишь ΠΏΠΎ ΡΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΡŽ Π²Π½ΡƒΡ‚Ρ€ΠΈ ошибки.

Π’ случаС примСнСния Anyhow, ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΈΠΌ Box<dyn>, ΠΏΡ€ΠΈ этом сразу Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ контСкстныС сообщСния, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠ½ΡΡ‚ΡŒ мСсто:

use anyhow::Context;
use base64::{self, engine, Engine};

fn decode() -> Result<(), anyhow::Error> {
    let input = std::fs::read_to_string("input")
    .context("Failed to read file")?; // контСкст 1
    for line in input.lines() {
        let bytes = engine::general_purpose::STANDARD
            .decode(line)
            .context("Failed to decode the input")?; // контСкст 2
        println!(
            "{}",
            String::from_utf8(bytes)
            .context("Failed to cenvert bytes")? // контСкст 3
        );
    }
    Ok(())

clap CLI

Установка

Π£ΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ вмСстС с Π΄ΠΎΠΏΠΎΠΌ derive, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ clap ΠΊΠ°ΠΊ ΠΏΡ€ΠΈΠ·Π½Π°ΠΊ (trait) Ρƒ структур Π΄Π°Π½Π½Ρ‹Ρ….

cargo add clap -F derive

Как ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ

Π”ΠΎΠ±Π°Π²ΠΊΠ° clap позволяСт ΠΏΠ°Ρ€ΡΠΈΡ‚ΡŒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки, Π° Ρ‚Π°ΠΊΠΆΠ΅ добавляСт ΠΊΠ»ΡŽΡ‡ΠΈ “-h” ΠΈ “–help” для ΠΏΠΎΠΌΠΎΡ‰ΠΈ Π±Π΅Π· ΠΊΠΎΠ΄Π°:

use clap::Parser;

#[derive(Parser, Debug)]
struct Args {
    arg1: String,
    arg2: usize,
}

fn main() {
    let args = Args::parse();
    println!("{:?}", args)
}

ΠŸΡ€ΠΈ запускС данная ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ 2 Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°, ΠΏΡ€ΠΈΡ‚ΠΎΠΌ Π²Ρ‚ΠΎΡ€ΠΎΠΉ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ числом.

Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ описаний

Имя ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΈ вСрсия вносятся ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΌ ΠΏΡ€ΠΈΠ·Π½Π°ΠΊΠΎΠΌ. Π”ΠΎΠΏ. поля описания вносятся с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ спСц. ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠ΅Π² ///:

use clap::Parser;

#[derive(Parser, Debug)]
#[command(author = "Author Name", version, about)]
/// A very simple CLI parser
struct Args {
    /// Text argument option
    arg1: String,
    /// Number argument option
    arg2: usize,
}

fn main() {
    let args = Args::parse();
    println!("{:?}", args)
}

Π”ΠΎΠ±Π°Π²ΠΊΠ° Ρ„Π»Π°Π³ΠΎΠ²

Π€Π»Π°Π³ΠΈ добавляСм с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π°Π½Π½ΠΎΡ‚Π°Ρ†ΠΈΠΈ #[arg(short, long)] для ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΎΠ³ΠΎ ΠΈ Π΄Π»ΠΈΠ½Π½ΠΎΠ³ΠΎ имСнования Ρ„Π»Π°Π³Π°. Если Ρƒ 2-Ρ… Ρ„Π»Π°Π³ΠΎΠ² одинаковая пСрвая Π±ΡƒΠΊΠ²Π°, ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ ΠΈΡ… ΠΊΠΎΡ€ΠΎΡ‚ΠΊΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ. ΠšΠΎΡ€ΠΎΡ‚ΠΊΠ°Ρ вСрсия Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ String, ΠΌΠΎΠΆΠ½ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ 1 char.

<..>
struct Args {
    #[arg(short = 'a', long)]
    /// Text argument option
    arg1: String,
    
    #[arg(short = 'A', long)]
    /// Number argument option
    arg2: usize,
}
<..>

ΠΠ΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Ρ„Π»Π°Π³ΠΈ

Для ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΊΠΈ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π° ΠΊΠ°ΠΊ Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ достаточно ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ Π΅Π³ΠΎ Ρ‚ΠΈΠΏ ΠΊΠ°ΠΊ Option<Ρ‚ΠΈΠΏ> ΠΈ Π² скобках исходный Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ…:

struct Args {
    #[arg(short = 'a', long)]
    /// Text argument option
    arg1: String,
    
    #[arg(short = 'A', long)]
    /// Number argument option
    arg2: Option<usize>,
}

Π’Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ ΠΏΠΎΡ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ ΡΠΈΡ‚ΡƒΠ°Ρ†ΠΈΡŽ, ΠΊΠΎΠ³Π΄Π° Π² arg2 Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅Ρ‚. ВмСсто Ρ‚Π°ΠΊ Π΄Π΅Π»Π°Ρ‚ΡŒ, ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ:

struct Args {
    #[arg(short = 'a', long)]
    /// Text argument option
    arg1: String,
    
    #[arg(default_value_t=usize::MAX, short = 'A', long)]
    /// Number argument option
    arg2: usize,
}

Π’Π΅ΠΏΠ΅Ρ€ΡŒ arg2 ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π²Π΅Π½ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½ΠΎΠΌΡƒ числу usize, Ссли Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½ΠΎ ΠΈΠ½ΠΎΠ΅.

Валидация Π²Π²Π΅Π΄Ρ‘Π½Π½Ρ‹Ρ… Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ

Π’ случаС Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°-строки Π΅ΡΡ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ввСсти ΠΏΡƒΡΡ‚ΡƒΡŽ строку ΠΈΠ· ΠΏΡ€ΠΎΠ±Π΅Π»ΠΎΠ² " ". Для ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Ρ‚Π°ΠΊΠΈΡ… Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠ², вводится функция Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΠΈ ΠΈ Π΅Ρ‘ Π²Ρ‹Π·ΠΎΠ²:

use clap::Parser;

#[derive(Parser, Debug)]
#[command(author = "Author Name", version, about)]
/// A very simple CLI parser
struct Args {
    #[arg(value_parser = validate_argument_name, short = 'a', long)]
    /// Text argument option
    arg1: String,
    #[arg(default_value_t=usize::MAX, short = 'A', long)]
    /// Number argument option
    arg2: usize,
}

fn validate_argument_name(name: &str) -> Result<String, String> {
    if name.trim().len() != name.len() {
        Err(String::from(
            "строка Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Π° Π½Π°Ρ‡ΠΈΠ½Π°Ρ‚ΡŒΡΡ ΠΈΠ»ΠΈ Π·Π°ΠΊΠ°Π½Ρ‡ΠΈΠ²Π°Ρ‚ΡŒΡΡ ΠΏΡ€ΠΎΠ±Π΅Π»Π°ΠΌΠΈ",
        ))
    } else {
        Ok(name.to_string())
    }
}

fn main() {
    let args = Args::parse();
    println!("{:?}", args)
}

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΡ€ΠΈ ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΠ΅ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ tiny-clapper -- -a " " Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠΊΠ°Π·Π°Π½Π° ошибка Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΠΈ.

Command CLI

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° позволяСт Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ Π² ОБ.

Π’Π°Ρ€ΠΈΠ°Π½Ρ‚Ρ‹ использования

  • spawn β€” runs the program and returns a value with details
  • output β€” runs the program and returns the output
  • status β€” runs the program and returns the exit code

ИспользованиС

Output - просто ΠΈ быстро

    let output = Command::new("cat")
        .arg("/etc/issue")
        .output()
        .with_context(|| "ls command failed")?;

    println!("{}", output.status);
    println!("{}", String::from_utf8_lossy(&output.stdout));
    println!("{}", String::from_utf8_lossy(&output.stderr));

β—ΠžΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ - ΠΌΠΎΠΆΠ½ΠΎ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹, нСльзя Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ свой тСкст.

spawn - Π³ΠΈΠ±ΠΊΠΈΠΉ Π²Π²ΠΎΠ΄

Π‘Π°ΠΌΡ‹ΠΉ Π³ΠΈΠ±ΠΊΠΈΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ Π΄Π΅Π»Π°Ρ‚ΡŒ свой Π²Π²ΠΎΠ΄, Π° Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ ΠΈ Ρ„Π°ΠΉΠ»Ρ‹-ΠΏΠ°ΠΏΠΊΠΈ, это Ρ‡Π΅Ρ€Π΅Π· spawn:

    let mut child = Command::new("cat") // ΠΊΠΎΠΌΠ°Π½Π΄Π°
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;

    let stdin = child.stdin.as_mut()?;
    stdin.write_all(b"Hello Rust!\n")?; // тСкст ΠΊ ΠΊΠΎΠΌΠ°Π½Π΄Π΅, /n обязатСлСн
    let output = child.wait_with_output()?;
    
    for i in output.stdout.iter() { // Ρ†ΠΈΠΊΠ» Π½Π° случай многострочного Π²Ρ‹Π²ΠΎΠ΄Π°
        print!("{}", *i as char);
    }
    Ok(())

β—ΠžΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ - ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ΄Π°Π²Π°Ρ‚ΡŒ Π½Π° Π²Ρ…ΠΎΠ΄ тСкст лишь Ρ‚Π΅ΠΌ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ сразу ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ Π²Π²ΠΎΠ΄Π½Ρ‹ΠΉ тСкст. ΠŸΡ€ΠΈ этом ряд ΠΊΠΎΠΌΠ°Π½Π΄ Π΄Π΅Π»Π°ΡŽΡ‚ ΠΏΠ°ΡƒΠ·Ρƒ ΠΏΠ΅Ρ€Π΅Π΄ ΠΏΠΎΡ‚Ρ€Π΅Π±Π»Π΅Π½ΠΈΠ΅ΠΌ тСкста Π½Π° Π²Ρ…ΠΎΠ΄, с Ρ‚Π°ΠΊΠΈΠΌΠΈ свой Π²Π²ΠΎΠ΄ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ это относится ΠΈ ΠΊ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠΈ Ρ‡Π΅Ρ€Π΅Π· pipe = | grep <...> ΠΈ Π°Π½Π°Π»ΠΎΠ³ΠΈ.

Pipe (nightly) - ΠΏΠΎΠ»Π½Ρ‹ΠΉ Π²Π²ΠΎΠ΄ (Π½Π΅ ΠΏΡ€ΠΎΠ²Π΅Ρ€Π΅Π½Π½Ρ‹ΠΉ способ)

https://doc.rust-lang.org/std/pipe/fn.pipe.html Для использования Π½ΡƒΠΆΠ΅Π½ nightly Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Rust

rustup install nightly
rustup default nightly

ИспользованиС:

#![feature(anonymous_pipe)] // Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² Rust Nightly
use std::pipe

let text = "| grep file".as_bytes();

// ЗапускаСм саму ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ
let child = Command::new("ls")
    .arg("/Users/test")
    .stdin({
        // НСльзя ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ просто строку Π² ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ
        // НуТно ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ»ΠΎΠ²Ρ‹ΠΉ дСскриптор (ΠΊΠ°ΠΊ Π² ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΌ stdin "pipe")
        // ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ создаём ΠΏΠ°Ρ€Ρƒ pipes Ρ‚ΡƒΡ‚
        let (reader, mut writer) = std::pipe::pipe().unwrap();

        // ПишСм строку Π² ΠΎΠ΄Π½Ρƒ pipe
        writer.write_all(text).unwrap();

        // Π΄Π°Π»Π΅Π΅ ΠΏΡ€Π΅Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ Π²Ρ‚ΠΎΡ€ΡƒΡŽ для ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ Π² ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ сразу ΠΏΡ€ΠΈ spawn. 
        Stdio::from(reader)
    })
    .spawn()?;

itertools

External link: https://docs.rs/itertools/latest/itertools/

Working with iterators

Sorting() a string of letters (with rev() - reverse order)

use itertools::Itertools;

let text = "Hello world";
let text_sorted = text.chars().sorted().rev().collect::<String>();
// rev() - Iterate the iterable in reverse
   
println!("Text: {}, Sorted Text: {}", text, text_sorted); 
// Text: Hello world, Sorted Text: wroollledH 

Counts() подсчёт количСства ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Ρ… элСмСнтов Π² Array

use itertools::Itertools;

let number_list = [1,12,3,1,5,2,7,8,7,8,2,3,12,7,7];
let mode = number_list.iter().counts(); // Itertools::counts() 
// Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Hashmap, Π³Π΄Π΅ ΠΊΠ»ΡŽΡ‡ΠΈ взяты ΠΈΠ· массива, значСния - частота
for (key, value) in &mode {  
    println!("Число {key} встрСчаСтся {value} Ρ€Π°Π·");  
 } 

rand

Generating random numbers

External links:

Using rand lib example:

use rand::Rng;

fn main() {
let secret_of_type = rand::rng().random::<u32>();
let secret = rand::rng().random_range(1..=100);

println!("Random nuber of type u32: {secret_of_type}");
println!("Random nuber from 1 to 100: {}", secret); }

Π’ старой вСрсии Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ примСнялся ΠΏΡ€ΠΈΠ·Π½Π°ΠΊ gen(), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π»ΠΈ Π² связи с Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ΠΌ gen() Π² Rust 2024.

regex

Π’Π½Π΅ΡˆΠ½ΠΈΠ΅ ссылки:

Установка

cargo add regex

REGEX ВыраТСния

Один символ

.             any character except new line (includes new line with s flag)
\d            digit (\p{Nd})
\D            not digit
\pX           Unicode character class identified by a one-letter name
\p{Greek}     Unicode character class (general category or script)
\PX           Negated Unicode character class identified by a one-letter name
\P{Greek}     negated Unicode character class (general category or script)

ΠšΠ»Π°ΡΡΡ‹ символов

[xyz]         A character class matching either x, y or z (union).
[^xyz]        A character class matching any character except x, y and z.
[a-z]         A character class matching any character in range a-z.
[[:alpha:]]   ASCII character class ([A-Za-z])
[[:^alpha:]]  Negated ASCII character class ([^A-Za-z])
[x[^xyz]]     Nested/grouping character class (matching any character except y and z)
[a-y&&xyz]    Intersection (matching x or y)
[0-9&&[^4]]   Subtraction using intersection and negation (matching 0-9 except 4)
[0-9--4]      Direct subtraction (matching 0-9 except 4)
[a-g~~b-h]    Symmetric difference (matching `a` and `h` only)
[\[\]]        Escaping in character classes (matching [ or ])

БовмСщСния символов

xy    concatenation (x followed by y)
x|y   alternation (x or y, prefer x)

ΠŸΠΎΠ²Ρ‚ΠΎΡ€Ρ‹ символов

x*        zero or more of x (greedy)
x+        one or more of x (greedy)
x?        zero or one of x (greedy)
x*?       zero or more of x (ungreedy/lazy)
x+?       one or more of x (ungreedy/lazy)
x??       zero or one of x (ungreedy/lazy)
x{n,m}    at least n x and at most m x (greedy)
x{n,}     at least n x (greedy)
x{n}      exactly n x
x{n,m}?   at least n x and at most m x (ungreedy/lazy)
x{n,}?    at least n x (ungreedy/lazy)
x{n}?     exactly n x

ΠŸΡƒΡΡ‚Ρ‹Π΅ символы

^     the beginning of text (or start-of-line with multi-line mode)
$     the end of text (or end-of-line with multi-line mode)
\A    only the beginning of text (even with multi-line mode enabled)
\z    only the end of text (even with multi-line mode enabled)
\b    a Unicode word boundary (\w on one side and \W, \A, or \z on other)
\B    not a Unicode word boundary

Π“Ρ€ΡƒΠΏΠΏΠΈΡ€ΠΎΠ²ΠΊΠ° ΠΈ Ρ„Π»Π°Π³ΠΈ

(exp)          numbered capture group (indexed by opening parenthesis)
(?P<name>exp)  named (also numbered) capture group (names must be alpha-numeric)
(?<name>exp)   named (also numbered) capture group (names must be alpha-numeric)
(?:exp)        non-capturing group
(?flags)       set flags within current group
(?flags:exp)   set flags for exp (non-capturing)

Π‘ΠΏΠ΅Ρ†-символы

\*          literal *, works for any punctuation character: \.+*?()|[]{}^$
\a          bell (\x07)
\f          form feed (\x0C)
\t          horizontal tab
\n          new line
\r          carriage return
\v          vertical tab (\x0B)
\123        octal character code (up to three digits) (when enabled)
\x7F        hex character code (exactly two digits)
\x{10FFFF}  any hex character code corresponding to a Unicode code point
\u007F      hex character code (exactly four digits)
\u{7F}      any hex character code corresponding to a Unicode code point
\U0000007F  hex character code (exactly eight digits)
\U{7F}      any hex character code corresponding to a Unicode code point

Π’ΠΈΠΏΡ‹ символов ΠΏΠΎ ASCII

[[:alnum:]]    alphanumeric ([0-9A-Za-z])
[[:alpha:]]    alphabetic ([A-Za-z])
[[:ascii:]]    ASCII ([\x00-\x7F])
[[:blank:]]    blank ([\t ])
[[:cntrl:]]    control ([\x00-\x1F\x7F])
[[:digit:]]    digits ([0-9])
[[:graph:]]    graphical ([!-~])
[[:lower:]]    lower case ([a-z])
[[:print:]]    printable ([ -~])
[[:punct:]]    punctuation ([!-/:-@\[-`{-~])
[[:space:]]    whitespace ([\t\n\v\f\r ])
[[:upper:]]    upper case ([A-Z])
[[:word:]]     word characters ([0-9A-Za-z_])
[[:xdigit:]]   hex digit ([0-9A-Fa-f])

ИспользованиС REGEX

Π‘Π²Π΅Ρ€ΠΊΠ° с is_match()

use regex::Regex;
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let input = "hello, world!";
    let pattern = Regex::new(r"hello, (world|universe)!")?;
    
    let is_match = pattern.is_match(input);
    println!("Is match: {}", is_match); // true
    Ok(())
}

Для простого выяснСния Ρ„Π°ΠΊΡ‚Π° совпадСния Π»ΡƒΡ‡ΡˆΠ΅ всСго ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ is_match ΠΊΠ°ΠΊ самым быстрым способом.

Поиск ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ совпадСния

    let pattern = regex::Regex::new(r"hello, (world|universe)!")?;
    let input = "hello, world!";
    let first_match = pattern.find(input);

    println!("First match: {}", first_match.unwrap().as_str());

ΠŸΠ΅Ρ€Π²ΠΎΠ΅ совпадСниС Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΠΌΠ΅Ρ‚ΡŒ Ρ‚ΠΈΠΏ Option<match>, Π° Π² случаС отсутствия совпадСний = None.

Поиск всСх совпадСний

    let pattern = regex::Regex::new(r"hello, (world|universe)!")?;
    let input = "hello, world! hello, universe!";
    let matches: Vec<_> = pattern.find_iter(input).collect(); // find_iter()
    matches.iter().for_each(|i| println!("{}", i.as_str()));
    // matches = Vec<match> ΠΈ содСрТит всС совпадСния

serde

Installing

Add serde framework with Derive feature to use it in structures and functions. Also add a separate serde_json lib for converting into specifically JSON:

cargo add serde -F derive
cargo add serde_json

Usage

Add serde, then mark the structures with Serialise, Deserialise traits and use serde_json for serialising:

use serde::{Deserialize, Serialize};

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub enum LoginRole {
    Admin,
    User,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct User {
    pub username: String,
    pub password: String,
    pub role: LoginRole,
}

pub fn get_default_users() -> HashMap<String, User> {
    let mut users = HashMap::new();
    users.insert(
        "admin".to_string(),
        User::new("admin", "password", LoginRole::Admin),
    );
    users.insert(
        "bob".to_string(),
        User::new("bob", "password", LoginRole::User),
    );
    users
}

pub fn get_users() -> HashMap<String, User> {
    let users_path = Path::new("users.json");
    if users_path.exists() {
        // Load the file!
        let users_json = std::fs::read_to_string(users_path).unwrap();
        let users: HashMap<String, User> = serde_json::from_str(&users_json).unwrap();
        users
    } else {
        // Create a file and return it
        let users = get_default_users();
        let users_json = serde_json::to_string(&users).unwrap();
        std::fs::write(users_path, users_json).unwrap();
        users
    }

sysinfo

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° для изучСния ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² систСмы ΠΈ систСмных рСсурсов. https://docs.rs/sysinfo/latest/sysinfo/

Установка

cargo add sysinfo

ИспользованиС

use sysinfo::{RefreshKind, System};

fn main() {
    let _sys = System::new_with_specifics(RefreshKind::nothing());
    println!("System name:             {:?}", System::name());
    println!("System kernel version:   {:?}", System::kernel_version());
    println!("System OS version:       {:?}", System::os_version());
    println!("System host name:        {:?}", System::host_name());
}

Π‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ RefreshKind::nothing() ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‚ΡΡ всС динамичСскиС Π²Π΅Ρ‰ΠΈ, Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ остаток свободной памяти, Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ° ЦПУ, ΡΠ΅Ρ‚ΡŒ ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅, Ρ‡Ρ‚ΠΎ драматичСски ускоряСт опрос систСмы.

МоТно частично ΠΎΠΏΡ€Π°ΡˆΠΈΠ²Π°Ρ‚ΡŒ Ρ€Π°Π·Π½Ρ‹Π΅ систСмныС рСсурсы, ΠΏΠΎ Π·Π°Π΄Π°Π½Π½Ρ‹ΠΌ ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»Π°ΠΌ.

Tokio tracing

Π’Π½Π΅ΡˆΠ½ΠΈΠ΅ ссылки:

ΠΠ°Π±Π»ΡŽΠ΄Π°Π΅ΠΌΠΎΡΡ‚ΡŒ / Observability

ΠΠ°Π±Π»ΡŽΠ΄Π°Π΅ΠΌΠΎΡΡ‚ΡŒ позволяСт ΠΏΠΎΠ½ΡΡ‚ΡŒ систСму ΠΈΠ·Π²Π½Π΅, задавая вопросы ΠΎ Π½Π΅ΠΉ, ΠΏΡ€ΠΈ этом Π½Π΅ зная Π΅Π΅ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½Π΅Π³ΠΎ устройства. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, ΠΎΠ½Π° позволяСт Π»Π΅Π³ΠΊΠΎ ΡƒΡΡ‚Ρ€Π°Π½ΡΡ‚ΡŒ Π½Π΅ΠΏΠΎΠ»Π°Π΄ΠΊΠΈ ΠΈ Ρ€Π΅ΡˆΠ°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹Π΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ «нСизвСстныС нСизвСстныС». Она Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ Π²Π°ΠΌ ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π½Π° вопрос Β«ΠΏΠΎΡ‡Π΅ΠΌΡƒ Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ происходит?Β».

Π§Ρ‚ΠΎΠ±Ρ‹ Π·Π°Π΄Π°Ρ‚ΡŒ эти вопросы ΠΎ вашСй систСмС, ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ ΠΏΠΎΠ»Π½Ρ‹ΠΉ Π½Π°Π±ΠΎΡ€ инструмСнтов. Π’ΠΎ Π΅ΡΡ‚ΡŒ ΠΊΠΎΠ΄ прилоТСния Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ сигналы, Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ трассировки, ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊΠΈ ΠΈ ΠΆΡƒΡ€Π½Π°Π»Ρ‹. ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ инструмСнтировано, ΠΊΠΎΠ³Π΄Π° Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°ΠΌ Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ инструмСнты для устранСния Π½Π΅ΠΏΠΎΠ»Π°Π΄ΠΎΠΊ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Ρƒ Π½ΠΈΡ… Π΅ΡΡ‚ΡŒ вся нСобходимая информация.

ВСрминология

  • Π‘ΠΎΠ±Ρ‹Ρ‚ΠΈΠ΅ ΠΆΡƒΡ€Π½Π°Π»Π° (Log event/message) - событиС, ΠΏΡ€ΠΎΠΈΠ·ΠΎΡˆΠ΅Π΄ΡˆΠ΅Π΅ Π² ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ;
  • ΠŸΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΠΊ (Span record) - запись ΠΏΠΎΡ‚ΠΎΠΊΠ° исполнСния Π² систСмС Π·Π° ΠΏΠ΅Ρ€ΠΈΠΎΠ΄ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ. Он Ρ‚Π°ΠΊΠΆΠ΅ выполняСт Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ контСкста для событий ΠΆΡƒΡ€Π½Π°Π»Π° ΠΈ родитСля для ΠΏΠΎΠ΄-ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΊΠΎΠ²;
  • Врасса (trace) - полная запись ΠΏΠΎΡ‚ΠΎΠΊΠ° исполнСния Π² систСмС ΠΎΡ‚ получСния запроса Π΄ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΈ ΠΎΡ‚Π²Π΅Ρ‚Π°. Π­Ρ‚ΠΎ ΠΏΠΎ сути ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΠΊ-Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ, ΠΈΠ»ΠΈ ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΉ ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΠΊ;
  • ΠŸΠΎΠ΄ΠΏΠΈΡΡ‡ΠΈΠΊ (subscriber) - Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅Ρ‚ способ сбора Π΄Π°Π½Π½Ρ‹Ρ… трассы, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, запись ΠΈΡ… Π² стандартный Π²Ρ‹Π²ΠΎΠ΄;
  • ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚ трассировки (Tracing Context): Π½Π°Π±ΠΎΡ€ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒΡΡ ΠΌΠ΅ΠΆΠ΄Ρƒ слуТбами

Установка

cargo add tracing
cargo add tracing-subscriber -F json

ИспользованиС

Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ

ΠŸΡ€ΠΎΡΡ‚Π°Ρ инициализация ΠΈ отслСТиваниС событий:

use tracing::info;

fn main() {
    // Установка глобального сборщика ΠΏΠΎ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
    tracing_subscriber::fmt::init();

    let number_of_yaks = 3;

    // Π½ΠΎΠ²ΠΎΠ΅ событиС, Π²Π½Π΅ ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΊΠΎΠ²
    info!(number_of_yaks, "preparing to shave yaks");
}

Ручная инициализация свойств подписчика для форматирования Π»ΠΎΠ³Π°:

fn setup_tracing() {
    let subscriber = tracing_subscriber::fmt()
        .json() // Π½ΡƒΠΆΠ½ΠΎ cargo add tracing-subscriber -F json
        .with_max_level(tracing::Level::TRACE) // МАΠ₯ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ логирования
        .compact() // ΠΊΠΎΠΌΠΏΠ°ΠΊΡ‚Π½Ρ‹ΠΉ Π»ΠΎΠ³
        .with_file(true) // ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ»-исходник
        .with_line_number(true) // ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ Π½ΠΎΠΌΠ΅Ρ€Π° строк ΠΊΠΎΠ΄Π°
        .with_thread_ids(true) // ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ ID ΠΏΠΎΡ‚ΠΎΠΊΠ° с событиСм
        .with_target(false) // Π½Π΅ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ†Π΅Π»ΡŒ (ΠΌΠΎΠ΄ΡƒΠ»ΡŒ) события
        .finish();

    tracing::subscriber::set_global_default(subscriber).unwrap();

    tracing::info!("Starting up");
    tracing::warn!("Are you sure this is a good idea?");
    tracing::error!("This is an error!");
}

Врассировка Π² синхронном Ρ€Π΅ΠΆΠΈΠΌΠ΅

use tracing::{instrument, warn};

#[instrument]
fn sync_tracing() {
    warn!("event 1");
    sync_tracing_sub();
}

#[instrument]
fn sync_tracing_sub() {
    warn!("event 2");
}

fn main() {
    setup_tracing();
    sync_tracing();
}

ΠœΠ°ΠΊΡ€ΠΎΡ #[instrument] автоматичСски создаёт ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΊΠΈ (spans) для Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, Π° подписчик (subscriber) настроСн Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΊΠΈ Π² stdout.

Врассировка ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² Π² асинхронном Ρ€Π΅ΠΆΠΈΠΌΠ΅

use tracing_subscriber::fmt::format::FmtSpan;

#[tracing::instrument] // инструмСнт слСдит Π·Π° Π²Ρ€Π΅ΠΌΠ΅Π½Π΅ΠΌ Ρ€Π°Π±ΠΎΡ‚Ρ‹
async fn hello() {
    tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
}

#[tokio::main] // cargo add tokio -F time,macros,rt-multi-thread
async fn main() -> anyhow::Result<()> {
    let subscriber = tracing_subscriber::fmt()
        .json()
        .compact()
        .with_file(true)
        .with_line_number(true)
        .with_thread_ids(true)
        .with_target(false)
        .with_span_events(FmtSpan::ENTER | FmtSpan::CLOSE) // Π²Ρ…ΠΎΠ΄ ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄
        .finish();                                   // ΠΏΠΎΡ‚ΠΎΠΊΠ° ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ

    tracing::subscriber::set_global_default(subscriber).unwrap();

    hello().await;
    Ok(())
}

Π’ ΠΈΡ‚ΠΎΠ³Π΅ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ Π»ΠΎΠ³ Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΏΠΎΡ‚ΠΎΠΊΠ° с Π²Ρ€Π΅ΠΌΠ΅Π½Π΅ΠΌ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΈ:

2024-12-24T14:30:17.378906Z  INFO ThreadId(01) hello: src/main.rs:3: {"message":"enter"} {}
2024-12-24T14:30:18.383596Z  INFO ThreadId(01) hello: src/main.rs:3: {"message":"enter"} {}
2024-12-24T14:30:18.383653Z  INFO ThreadId(01) hello: src/main.rs:3: {"message":"enter"} {}
2024-12-24T14:30:18.383675Z  INFO ThreadId(01) hello: src/main.rs:3: {"message":"close","time.busy":"179Β΅s","time.idle":"1.00s"} {}

Π—Π°ΠΏΠΈΡΡŒ ΠΆΡƒΡ€Π½Π°Π»Π° Π² Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅

Π’Π½Π΅ΡˆΠ½ΠΈΠ΅ ссылки:

Для записи ΠΆΡƒΡ€Π½Π°Π»Π° примСняСтся ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ tracing-appender:

cargo add tracing-appender

Π£ Π½Π΅Π³ΠΎ ΠΌΠ½ΠΎΠ³ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ записи Π² ΠΎΠ±Π»Π°Ρ‡Π½Ρ‹Π΅ слуТбы Ρ‚ΠΈΠΏΠ° Datadog, Π½ΠΎ ΠΈ созданиС ΠΆΡƒΡ€Π½Π°Π»Π° с дозаписью (ΠΌΠΈΠ½ΡƒΡ‚Π½ΠΎΠΉ, часовой, Π΄Π½Π΅Π²Π½ΠΎΠΉ), Π° Ρ‚Π°ΠΊΠΆΠ΅ запись ΠΊΠ°ΠΊ Π½Π΅Π±Π»ΠΎΠΊΠΈΡ€ΡƒΡŽΡ‰Π΅Π΅ дСйствиС Π²ΠΎ врСмя ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡ‚ΠΎΡ‡Π½ΠΎΠ³ΠΎ исполнСния.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ Π½Π΅Π±Π»ΠΎΠΊΠΈΡ€ΡƒΡŽΡ‰Π΅ΠΉ записи ΠΆΡƒΡ€Π½Π°Π»Π° Π² Ρ„Π°ΠΉΠ» (Π»ΡƒΡ‡ΡˆΠ΅ всСго ΠΊΠ°ΠΊ JSON), ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ Π²Ρ‹Π²ΠΎΠ΄ Π½Π° экран ΠΈ организация часового ΠΆΡƒΡ€Π½Π°Π»Π° с дозаписью (rolling):

use tracing::{instrument, warn};

// тянСм std::io::Write ΠΏΡ€ΠΈΠ·Π½Π°ΠΊ Π² Ρ€Π΅ΠΆΠΈΠΌΠ΅ нСблокирования
use tracing_subscriber::fmt::writer::MakeWriterExt; 

fn setup_tracing() {
    // инициализация Ρ„Π°ΠΉΠ»Π° с дозаписью
    let logfile = tracing_appender::rolling::hourly("/some/directory", "app-log");
    // ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ записи ΠΏΡ€ΠΈ Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ = INFO
    let stdout = std::io::stdout.with_max_level(tracing::Level::INFO);

    let subscriber = tracing_subscriber::fmt()
        .with_max_level(tracing::Level::TRACE)
        .json()
        .compact()
        .with_file(true)
        .with_line_number(true)
        .with_thread_ids(true)
        .with_target(false)
        .with_writer(stdout.and(logfile)) // ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ запись Ρ‚ΡƒΡ‚
        .finish();                        // Π² Ρ„Π°ΠΉΠ» ΠΈ Π² stdout консоль
    tracing::subscriber::set_global_default(subscriber).unwrap();
}

#[instrument]
fn sync_tracing() {
    warn!("event 1");
    sync_tracing_sub();
}

#[instrument]
fn sync_tracing_sub() {
    warn!("event 2");
}

fn main() {
    setup_tracing();
    sync_tracing();
}

CLI Arguments

ARGS

АргумСнты ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки ΠΌΠΎΠΆΠ½ΠΎ Π·Π°Ρ…Π²Π°Ρ‚ΠΈΡ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² args()+collect() Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ env. НуТно ΠΏΠΎΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ ΠΈΡ… Π² строковый Π²Π΅ΠΊΡ‚ΠΎΡ€.

use std::env;  
  
fn main() {  
    let args: Vec<String> = env::args().collect();  
  
    for arg in args.iter() {  
        println!("{}", arg);  
    } }

ΠŸΠ΅Ρ€Π²Ρ‹ΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² всСгда ΠΈΠ΄Ρ‘Ρ‚ имя самой ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹.

Tip

ΠŸΡ€ΠΎΠ΄Π²ΠΈΠ½ΡƒΡ‚ΡƒΡŽ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² CLI ΡƒΠ΄ΠΎΠ±Π½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Clap

Closures

Closure

  • Замыкания ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΈΡΠ²ΠΎΠΈΡ‚ΡŒ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΌ ΠΈ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ;
  • Π’ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, замыкания ΠΌΠΎΠ³ΡƒΡ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ Π²Π½Π΅ своСго Π±Π»ΠΎΠΊΠ°.
(0..3).for_each(|x| {println!("map i = {}", x * 2);});

Map ΠΈ Filter

.map(<closure>) ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘Ρ‚ Π²Π»Π°Π΄Π΅Π½ΠΈΠ΅ элСмСнтами ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€Π° Π·Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΡŽ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΡ… ΠΌΠΎΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ Ρ‚Ρ€Π°Π½ΡΡ„ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π² Π΄Ρ€ΡƒΠ³ΠΈΠ΅ элСмСнты, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΄Π°Π»Π΅Π΅ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π·Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΠ΅.

.filter(<closure>) Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹Π΅ элСмСнты, ΠΊΠΎΠ³Π΄Π° ΠΏΡ€Π΅Π΄ΠΈΠΊΠ°Ρ‚ замыкания Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ true. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, ΠΎΡ‚Π΄Π°Π²Π°Ρ‚ΡŒ Π²Π»Π°Π΄Π΅Π½ΠΈΠ΅ элСмСнтами Π·Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΡŽ нСльзя, ΠΈ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ ΠΏΠΎ ссылкС.

let a = (0..3).map(|x| x * 2);
for i in a {
    println!("map i = {}", i);
}

let a = (0..3).filter(|&x| x % 2 == 0);
for i in a {
    println!("filter i = {}", i);
}

Π’Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ замыкания map()

    let a = (0..=3).map(|x| x * 2).map(|y| y - 1);
    // пСрвая итСрация map(): 2, 4, 6
    // вторая итСрация map(): 1, 3, 5
    for i in a {
        println!("{i}");
    }

Fold

КаТдая итСрация fold ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ 2 Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°:

  • Π˜ΡΡ…ΠΎΠ΄Π½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ счётчика;
  • Π—Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Ρ‚ΠΎΠΆΠ΅ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ 2 Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°: счётчик ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚. Π—Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΠ΅ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ счётчик.

fold ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для прСвращСния мноТСства Π² 1 Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅. ΠŸΡ€ΠΈΠΌΠ΅Ρ€ для получСния суммы всСх Ρ‡Ρ‘Ρ‚Π½Ρ‹Ρ… чисСл:

pub fn main() {
    let even_sum = (1..=10).fold(0, |acc, num| if num % 2 == 0 { acc + num } else { acc });
    println!("{even_sum:?}");
}

fold ΠΌΠΎΠΆΠ½ΠΎ часто Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌΠΈ. НапримСр, ΠΊΠΎΠ΄ Π²Ρ‹ΡˆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π½Π° ΠΎΡ‚Π±ΠΎΡ€ всСх Ρ‡Ρ‘Ρ‚Π½Ρ‹Ρ… числС с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ filter ΠΈ ΠΈΡ… слоТСниС с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ sum:

(0..=10).filter(|n| *n % 2 == 0).sum()

НаравнС с sum Ρ‚Π°ΠΊΠΆΠ΅ популярны product ΠΈ collect.

Π‘Ρ‡Ρ‘Ρ‚Ρ‡ΠΈΠΊ Ρƒ fold Π½Π΅ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ числовой, ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, String:

pub fn giant_grunts(initial: char) -> String {
    ["Bee", "Fee", "Gee", "Fi", "Hi", "Fo", "Mo", "Fum", "Tum"].iter().fold(
        String::new(),
        |acc, grunt| if grunt.starts_with(initial) { acc + grunt } else { acc },
    )}

pub fn main() {
    let song = giant_grunts('F');
    println!("{song:?}"); // "FeeFiFoFum" 
}

All

Π—Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΠ΅ all Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ True, Ссли всС элСмСнты Π² Π·Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΠΈ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‚ ΡƒΡΠ»ΠΎΠ²ΠΈΡŽ.

let a: Vec<i32> = vec![1, 2, 3, 4];
print!("{}\n", a.into_iter().all(|x| x > 1)); // false

Для пустого Π²Π΅ΠΊΡ‚ΠΎΡ€Π° Π·Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΠ΅ all Π²Π΅Ρ€Π½Ρ‘Ρ‚ True:

let a: Vec<i32> = vec![];
print!("{}\n", a.into_iter().all(|x| x > 1)); // true

Π¦ΠΈΠΊΠ» Ρ‡Π΅Ρ€Π΅Π· Π·Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΠ΅ vs for

use std::collections::HashMap;
pub fn main() {
    let num_vec = vec![1, 2, 1, 3, 5, 2, 1, 4, 6];
    let mut number_count: HashMap<i32, i32> = HashMap::new();
    for key in num_vec {
        *number_count.entry(key).or_default() += 1;
    }
    /* for (k, v) in number_count {
        print!("{} -> {}; ", k, v);
    } */
    
    number_count.iter().for_each(|(k, v)| {
        print!("{} -> {}; ", k, v);
    }); //Ρ†ΠΈΠΊΠ» Ρ‡Π΅Ρ€Π΅Π· Π·Π°ΠΌΡ‹ΠΊΠ°Π½ΠΈΠ΅ ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°
}

Constants

ΠšΠΎΠ½ΡΡ‚Π°Π½Ρ‚Ρ‹

Π­Ρ‚ΠΎ Π³Π»ΠΎΠ±Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠΎ области дСйствия значСния, нСизмСняСмыС. ΠŸΡ€ΠΈ объявлСнии Π½ΡƒΠΆΠ½ΠΎ всСгда сразу ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ ΠΈΡ… Ρ‚ΠΈΠΏ.

const MAX_LIMIT: u8 = 15;  // Ρ‚ΠΈΠΏ u8 ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ Π½Π°Π΄ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ
  
fn main() {  
    for i in 1..MAX_LIMIT {  
        println!("{}", i);  
    }  }

Cross-compiling

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° систСмы

Π‘Π΄Π΅Π»Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π² Π½Π΅Π³ΠΎ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ cargoΒ addΒ current_platform. Π”Π°Π»Π΅Π΅ создаём ΠΈ запускаСм ΠΊΠΎΠ΄ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ срСды компиляции ΠΈ исполнСния:

use current_platform::{COMPILED_ON, CURRENT_PLATFORM};

fn main() {
    println!("Run from {}! Compiled on {}.", CURRENT_PLATFORM, COMPILED_ON);
}
  • ΠŸΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ‚Π΅ΠΊΡƒΡ‰ΡƒΡŽ ОБ компиляции: rustc -vV
  • ΠŸΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ список ОБ для кросс-компиляции: rustc --print target-list Π€ΠΎΡ€ΠΌΠ°Ρ‚ списка ΠΈΠΌΠ΅Π΅Ρ‚ поля <arch><sub>-<vendor>-<sys>-<env>, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, x86_64-apple-darwin => macOS Π½Π° Ρ‡ΠΈΠΏΠ΅ Intel.

Настройка кросс-компилятора

НуТно ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ cross: cargo install cross установит Π΅Π³ΠΎ ΠΏΠΎ ΠΏΡƒΡ‚ΠΈ $HOME/.cargo/bin

Π”Π°Π»Π΅Π΅, Π½ΡƒΠΆΠ½ΠΎ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Docker Π² систСмС:

  • На macOS => Docker Desktop;
  • На Linux => Podman

Запуск ΠΊΠΎΠ΄Π° Π½Π° ΠΊΠΎΠΌΠΏΠΈΠ»ΡΡ†ΠΈΡŽ ΠΏΠΎΠ΄ ОБ Windows: cross run --target x86_64-pc-windows-gnu => Π² ΠΏΠ°ΠΏΠΊΠ΅ target/x86_64-pc-windows-gnu/debug ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ EXE-Ρ„Π°ΠΉΠ» с Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ. β—ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ†ΠΈΡ ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ Ρ‡Π΅Ρ€Π΅Π· WINE.

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° срСды компиляции

Cross ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ тСстированиС Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌ. Π”ΠΎΠ±Π°Π²ΠΊΠ° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ:

mod tests {
    use current_platform::{COMPILED_ON, CURRENT_PLATFORM};

    #[test]
    fn test_compiled_on_equals_current_platform() {
        assert_eq!(COMPILED_ON, CURRENT_PLATFORM);
    } }

Π—Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΡƒ локально: cargo test Π—Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΡƒ с кросс-компиляциСй: cross test --target x86_64-pc-windows-gnu На Linux/macOS ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΏΡ€ΠΎΠΉΠ΄Ρ‘Ρ‚, Π° Π²ΠΎΡ‚ ΠΏΡ€ΠΈ компиляции ΠΏΠΎΠ΄ Windows - Π½Π΅Ρ‚: `test tests::test_compiled_on_equals_current_platform … FAILED

Π”ΠΎΠ±Π°Π²ΠΊΠ° ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Π½Π½ΠΎ-спСцифичного ΠΊΠΎΠ΄Π°

МоТно Π²ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΊΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ запустится Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠΉ ОБ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° Windows:

use current_platform::{COMPILED_ON, CURRENT_PLATFORM};

#[cfg(target_os="windows")]
fn windows_only() {
    println!("This will only print on Windows!");
}

fn main() {
    println!("Run from {}! Compiled on {}.", CURRENT_PLATFORM, COMPILED_ON);
    #[cfg(target_os="windows")]
    {
        windows_only();
    }
}

Enums

ΠŸΠ΅Ρ€Π΅Ρ‡ΠΈΡΠ»Π΅Π½ΠΈΡ

Π’ΠΈΠΏ пСрСчислСний позволяСт ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π²Ρ‹Π±ΠΎΡ€ ΠΈΠ· Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠ² Π² ΠΏΡ€Π΅Π΄Π΅Π»Π°Ρ… логичСского мноТСства.

enum Money {  
    Rub,  
    Kop  
}

match

Аналог switch Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… языках, ΠΎΠ΄Π½Π°ΠΊΠΎ, ΠΊΡ€ΡƒΡ‡Π΅: Π΅Π³ΠΎ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π½Π΅ сводится ΠΊ bool, Π° Ρ‚Π°ΠΊΠΆΠ΅ рСакция Π½Π° ΠΊΠ°ΠΆΠ΄ΠΎΠ΅ дСйствиС ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π±Π»ΠΎΠΊΠΎΠΌ:

fn main() {  
    let m = Money::Kop;  
    println!("Π― Π½Π°ΡˆΡ‘Π» ΠΊΠΎΡˆΠ΅Π»Ρ‘ΠΊ, Π° Ρ‚Π°ΠΌ {}p",match_value_in_kop(m));  
}  
  
fn match_value_in_kop(money: Money) -> u8 {  
    match money {  
        Money::Rub => 100,  
        Money::Kop => {  
            println!("Бчастливая ΠΊΠΎΠΏΠ΅ΠΉΠΊΠ°!");  
            1  
        }  }  }

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° условия ΠΈ запуск ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°:

struct State {
    color: (u8, u8, u8),
    position: Point,
    quit: bool,
}

impl State {
    fn change_color(&mut self, color: (u8, u8, u8)) {
        self.color = color; }

    fn quit(&mut self) {
        self.quit = true; }

    fn echo(&self, s: String) {
        println!("{}", s); }

    fn move_position(&mut self, p: Point) {
        self.position = p; }

    fn process(&mut self, message: Message) {
        match message { // ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΈ запуск ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΈΠ· ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ²
            Message::Quit => self.quit(),
            Message::Echo(x) => self.echo(x),
            Message::ChangeColor(x, y, z) => self.change_color((x, y, z)),
            Message::Move(x) => self.move_position(x),
        } } }

if let

Π’ случаС, ΠΊΠΎΠ³Π΄Π° Π²Ρ‹Π±ΠΎΡ€ сводится ΠΊ Ρ‚ΠΎΠΌΡƒ, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ сравниваСм 1 Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ с Π·Π°Π΄Π°Π½Π½Ρ‹ΠΌ ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½ΠΎΠΌ ΠΈ Π΄Π°Π»Π΅Π΅ запускаСм ΠΊΠΎΠ΄ ΠΏΡ€ΠΈ успСхС, Π° Π² случаС нСравСнства Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ Π΄Π΅Π»Π°Π΅ΠΌ, ΠΌΠΎΠΆΠ½ΠΎ вмСсто match ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡ‚ΡŒ Π±ΠΎΠ»Π΅Π΅ ΠΊΠΎΡ€ΠΎΡ‚ΠΊΡƒΡŽ ΠΊΠΎΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ if-let:

    let config_max = Some(3u8);
    match config_max {
        Some(max) => println!("The maximum is configured to be {}", max),
        _ => (), //  Π΄Ρ€ΡƒΠ³ΠΈΠ΅ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Ρ‹ Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‚
    }

ΠŸΡ€Π΅Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ΡΡ Π²:

    let config_max = Some(3u8);
    if let Some(max) = config_max {
        println!("The maximum is configured to be {}", max);
    }

ΠŸΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ if-let - это синтаксичСский сахар, ΡƒΠΊΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅Ρ‚ ΠΊΠΎΠ΄, ΠΎΠ΄Π½Π°ΠΊΠΎ, Π»ΠΈΡˆΠ°Π΅Ρ‚ нас ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ наличия ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ² Π½Π° всС Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Ρ‹ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Ρ… Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ ΠΊΠ°ΠΊ Π² конструкции match.

Π‘Ρ€Π°Π²Π½Π΅Π½ΠΈΠ΅ Π²Π΅Π»ΠΈΡ‡ΠΈΠ½

Для сравнСния Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Π² ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… Π΅ΡΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ std::cmp, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Ρ‚ΠΈΠΏΠ° enum Ordering с Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π°ΠΌΠΈ:

use std::cmp::Ordering;
use std:io;

fn main() {
let secret_number = 42;
let mut guess = String::new();
io::stdin()
.read_line(&guess)
.expect("Read line failed!");
  
let guess :i32 = guess.trim().parse()
  .expect("Error! Non-number value entered.");

match guess.cmp(&secret_number) {
  Ordering::Greater => println!("Number too big"),
  Ordering::Less => println!("Number too small"),
  Ordering::Equal => println("Found exact number!")
 }
}

Error Handling

Π’Π½Π΅ΡˆΠ½ΠΈΠ΅ ссылки:

Ошибки Π±Π΅Π· восстановлСния

Ряд ошибок ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ ΠΊ Π²Ρ‹Π»Π΅Ρ‚Ρƒ прилоТСния. Π’Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ Π²Ρ‹Π»Π΅Ρ‚ ΠΊΠΎΠΌΠ°Π½Π΄ΠΎΠΉ panic!:

fn main() {
    panic!("Battery critically low! Shutting down to prevent data loss.");
}

ΠŸΡ€ΠΈ этом Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ врСмя тратится Π½Π° Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ прилоТСния, очистку стСка ΠΈ Π΄Π°Π½Π½Ρ‹Ρ…. МоТно ΠΏΠ΅Ρ€Π΅Π»ΠΎΠΆΠΈΡ‚ΡŒ это Π½Π° ОБ, ввСдя настройку Π² Cargo.toml:

[profile.release]
panic = 'abort'

ΠŸΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°

Допустим, ΠΌΡ‹ Π±Π΅Ρ€Ρ‘ΠΌ Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΈΠ· строк-чисСл, складываСм ΠΈΡ… ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ сумму ΠΊΠ°ΠΊ строку:

fn sum_str_vec (strs: Vec<String>) -> String {  
    let mut accum = 0i32;  
    for s in strs {  
        accum += to_int(&s); // to_int = Π·Π°Π³ΠΎΡ‚ΠΎΠ²ΠΊΠ°, см. Π½ΠΈΠΆΠ΅ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ 
    }  
    return accum.to_string();  
}  
  
fn main() {  
    let v = vec![String::from("3"), String::from("4")]; // ΠŸΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ Π²Π²ΠΎΠ΄ 
    let total = sum_str_vec(v);  
    println!("Total equals: {:?}", total);  
  
    let v = vec![String::from("3"), String::from("abc")]; // ΠΠ΅ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ Π²Π²ΠΎΠ΄ 
    let total = sum_str_vec(v);  
    println!("Total equals: {:?}", total);  
}

Для ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΠΈ строки Π² числа, Π½ΡƒΠΆΠ½ΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ to_int Π² соотвСтствии со стратСгиями ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΎΡˆΠΈΠ±ΠΎΡ‡Π½ΠΎΠ³ΠΎ Π²Π²ΠΎΠ΄Π°. ΠšΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΡŽ ΠΌΡ‹ Π΄Π΅Π»Π°Π΅ΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ parse(), которая Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ‚ΠΈΠΏ Result<T,E>, Π³Π΄Π΅ T - Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, E - ΠΊΠΎΠ΄ ошибки.

БтратСгия 1 - ΠΏΠ°Π½ΠΈΠΊΠ°

Π’ случаС Π½Π΅Π²Π΅Ρ€Π½ΠΎΠ³ΠΎ Π²Π²ΠΎΠ΄Π°, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ останавливаСтся Π² ΠΏΠ°Π½ΠΈΠΊΠ΅. ΠœΠ΅Ρ‚ΠΎΠ΄ unwrap() Ρƒ Ρ‚ΠΈΠΏΠ° Result<T,E> ΡƒΠ±ΠΈΡ€Π°Π΅Ρ‚ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Π½Π° ошибки ΠΈ Π΅ΡΡ‚ΡŒ Π΄ΠΎΠ³ΠΎΠ²ΠΎΡ€ с компилятором ΠΎ Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ ошибки Π² этом мСстС Π±Ρ‹Ρ‚ΡŒ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚. Если ΠΎΠ½Π° Π΅ΡΡ‚ΡŒ, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° ΠΏΠ°Π΄Π°Π΅Ρ‚ с ΠΏΠ°Π½ΠΈΠΊΠΎΠΉ:

fn to_int(s: &str) -> i32 {  
    s.parse().unwrap() } 

БтратСгия 2 - ΠΏΠ°Π½ΠΈΠΊΠ° с ΡƒΠΊΠ°Π·Π°Π½ΠΈΠ΅ΠΌ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Ρ‹

Π’ случаС Π½Π΅Π²Π΅Ρ€Π½ΠΎΠ³ΠΎ Π²Π²ΠΎΠ΄Π°, ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° сообщаСт Ρ„Ρ€Π°Π·Ρƒ, Π·Π°Π΄Π°Π½Π½ΡƒΡŽ Π°Π²Ρ‚ΠΎΡ€ΠΎΠΌ, Π΄Π°Π»Π΅Π΅ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ останавливаСтся Π² ΠΏΠ°Π½ΠΈΠΊΠ΅. ΠœΠ΅Ρ‚ΠΎΠ΄ expect() Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π΅Π½ unwrap(), Π½ΠΎ Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ сообщСниС:

fn to_int(s: &str) -> i32 {  
    s.parse().expect("Error converting from string") } 

БтратСгия 3 - ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ

МоТно ΡΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ ΠΏΡ€ΠΈΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρƒ Ρ‚Π΅ строки, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ это ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ, ΠΏΡ€ΠΎΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅. ΠœΠ΅Ρ‚ΠΎΠ΄ unwrap_or() позволяСт ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² случаС ошибки:

fn to_int(s: &str) -> i32 {  
    s.parse().unwrap_or(0) } // ΠΏΡ€ΠΈ Π²Π²ΠΎΠ΄Π΅ "abc" вСрнётся 0, сумма = "3" 

Π‘ΠΎΠ»Π΅Π΅ ΠΏΡ€Π΅Π΄ΠΏΠΎΡ‡Ρ‚ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ unwrap_or_else(), Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΌΠ΅Ρ‚ΠΎΠ΄ unwrap_or() Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π·Π²Π°Π½ Π”Πž Ρ‚ΠΎΠ³ΠΎ ΠΊΠ°ΠΊ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Π½Π° основная ΠΊΠΎΠΌΠ°Π½Π΄Π°, ВНЕ Π—ΠΠ’Π˜Π‘Π˜ΠœΠžΠ‘Π’Π˜ ΠΎΡ‚ Ρ‚ΠΎΠ³ΠΎ, Π±ΡƒΠ΄Π΅Ρ‚ Π»ΠΈ Π΅Ρ‘ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Some ΠΈΠ»ΠΈ None. Π­Ρ‚ΠΎ потСря ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ глюки ΠΏΡ€ΠΈ использовании Π²Π½ΡƒΡ‚Ρ€ΠΈ unwrap_or() слоТных Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ. Π—Π°ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ unwrap_or_else() Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π·Π²Π°Π½ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² случаС None, ΠΈΠ½Π°Ρ‡Π΅ ΠΆΠ΅ эта Π²Π΅Ρ‚ΠΊΠ° Π½Π΅ обрабатываСтся:

fn to_int(s: &str) -> i32 {  
    s.parse().unwrap_or_else(|_| 0) }

БтратСгия 4 - Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‰Π°Ρ функция

ВмСсто Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π° числа, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ Ρ‚ΠΈΠΏ Option<число> - Π² зависимости ΠΎΡ‚ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΡΡ‚ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π² Π½Ρ‘ΠΌ Π±ΡƒΠ΄Π΅Ρ‚ Π»ΠΈΠ±ΠΎ само число, Π»ΠΈΠ±ΠΎ None:

fn to_int(s: &str) -> Option<i32> {  
    s.parse().ok() // ok() ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚ Result<T,E> Π² Option<T> 

И Ρ‚ΠΎΠ³Π΄Π° Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‰Π°Ρ функция Π΄ΠΎΠ»ΠΆΠ½Π° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚:

fn sum_str_vec (strs: Vec<String>) -> String {  
    let mut accum = 0i32;  
    for s in strs {  
        accum += match to_int(&s) {  
            Some(v) => v,  
            None => {  
                println!("Error converting a value, skipped");  
                0  // вСрнётся 0 +Π² Π»ΠΎΠ³ ΠΏΠΎΠΉΠ΄Ρ‘Ρ‚ запись ΠΎ пропускС
            }, }  }  
    return accum.to_string();  
}

Π‘ΠΎΠ»Π΅Π΅ ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΈΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ записи Ρ‡Π΅Ρ€Π΅Π· if let:

fn sum_str_vec (strs: Vec<String>) -> String {  
    let mut accum = 0i32;  
    for s in strs {  
        if let Some(val) = to_int(&s) {  
            accum += val;  
        } else { println!("Error converting a value, skipped"); }  
    }  
    return accum.to_string();  
}

Π’ΠΈΠΏ Option<T> Ρ‚Π°ΠΊΠΆΠ΅ ΠΈΠΌΠ΅Π΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ unwrap_or(), ΠΎΡ‚ΡΡŽΠ΄Π° Π΅Ρ‰Ρ‘ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ записи:

fn sum_str_vec (strs: Vec<String>) -> String {  
    let mut accum = 0i32;  
    for s in strs {  
        accum += to_int(&s).unwrap_or(0); // раскрываСм Option<T> 
    }  
    return accum.to_string();  
}

БтратСгия 5 - Π² случаС ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ всё Π² ΠΎΡΠ½ΠΎΠ²Π½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ

ВмСсто ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ значСния ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π² случаС ΠΊΠ°ΠΊΠΈΡ…-Π»ΠΈΠ±ΠΎ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ, ΠΌΡ‹ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ None:

fn sum_str_vec (strs: Vec<String>) -> Option<String> {  
    let mut accum = 0i32;  
    for s in strs {  
        accum += to_int(&s)?;  // Π² случаС None, ? ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘Ρ‚ Π΅Π³ΠΎ Π΄Π°Π»Π΅Π΅ Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄
    }                         
    Some(accum.to_string())    // Π½Π° Π²Ρ‹Ρ…ΠΎΠ΄ ΠΏΠΎΠΉΠ΄Ρ‘Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ None
}

БтратСгия 6 - ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ всё Π² ΠΎΡΠ½ΠΎΠ²Π½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ с объяснСниСм ошибки

ΠœΡ‹ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ Π² ΠΎΡΠ½ΠΎΠ²Π½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ с объясСниСм ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹. Для этого Π·Π°Π²ΠΎΠ΄ΠΈΠΌ структуру ΠΏΠΎΠ΄ ΠΎΡˆΠΈΠ±ΠΊΡƒ, ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘ΠΌ ΡƒΠΆΠ΅ Π½Π΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Option<T>, Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Result<T,E>, Π³Π΄Π΅ E = SummationError. Для Ρ‚Π°ΠΊΠΎΠ³ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Π΅ΡΡ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ ok_or(), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π»ΠΈΠ±ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, Π»ΠΈΠ±ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘Ρ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ Π½ΡƒΠΆΠ½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°:

#[derive(Debug)]  
struct SummationError;

fn sum_str_vec (strs: Vec<String>) -> Result<String, SummationError> {  
    let mut accum = 0i32;  
    for s in strs {  
        accum += to_int(&s).ok_or(SummationError)?;  
    }  
    Ok(accum.to_string())  
}

ВмСсто Π²Ρ‹Π΄ΡƒΠΌΡ‹Π²Π°Ρ‚ΡŒ свой собствСнный Ρ‚ΠΈΠΏ ΠΈ ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π²Ρ‹Π²ΠΎΠ΄ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° parse() ΠΈΠ· Result<T,E> Π² Option<T>, Π° ΠΏΠΎΡ‚ΠΎΠΌ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ, ΠΌΠΎΠΆΠ½ΠΎ сразу ΠΏΡ€ΠΎΡ‚Π°Ρ‰ΠΈΡ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ Π² ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π΅ Result<T,E> Π² Π³Π»Π°Π²Π½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ:

use std::num::ParseIntError;  // Ρ‚ΠΈΠΏ ошибки Π±Π΅Ρ€Ρ‘ΠΌ ΠΈΠ· Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ
  
fn to_int(s: &str) -> Result<i32, ParseIntError> {  
    s.parse()  // parse Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ просто Result<T,E>
}  
  
fn sum_str_vec (strs: Vec<String>) -> Result<String, ParseIntError> {  
    let mut accum = 0i32;  
    for s in strs {  
        accum += to_int(&s)?; }  // ? ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘Ρ‚ ΠΎΡˆΠΈΠ±ΠΊΡƒ Π½ΡƒΠΆΠ½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° Π΄Π°Π»Π΅Π΅
    Ok(accum.to_string())  
}

Однако, ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ ΡΠΊΡ€Ρ‹Ρ‚ΡŒ подробности Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΈ ошибки ΠΎΡ‚ Π³Π»Π°Π²Π½ΠΎΠΉ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ Π΅ΠΉ ΠΎΡˆΠΈΠ±ΠΊΡƒ Π² понятном Π²ΠΈΠ΄Π΅, Π±Π΅Π· Ρ€Π°Π·ΡŠΡΡΠ½Π΅Π½ΠΈΡ Π΄Π΅Ρ‚Π°Π»Π΅ΠΉ Π΅Ρ‘ возникновСния. Для этого ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Ρ‚Ρ€Π°Π½ΡΠ»ΡΡ†ΠΈΡŽ ошибки ΠΈΠ· Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅Ρ‡Π½ΠΎΠΉ Π² собствСнный Ρ‚ΠΈΠΏ, ΠΈ Π΄Π°Π»Π΅Π΅ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠΌ map_err():

use std::num::ParseIntError;  
  
#[derive(Debug)]  
struct SummationError;  
  
fn to_int(s: &str) -> Result<i32, ParseIntError> {  
    s.parse()  
}  
  
fn sum_str_vec (strs: Vec<String>) -> Result<String, SummationError> {  
    let mut accum = 0i32;  
    for s in strs {  
        accum += to_int(&s).map_err(|_| SummationError)?; // конвСртация ошибки  
    }                                                     // ΠΏΠ΅Ρ€Π΅Π΄ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ΠΉ
    Ok(accum.to_string())  
}

Π“Π΄Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ ?

ΠžΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ ? ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² функциях для Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π° совмСстимых Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Ρ‚ΠΈΠΏΠ° Result<T,E>, Option<T> ΠΈΠ»ΠΈ ΠΈΠ½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ… со свойством FromResidual. Для Ρ€Π°Π±ΠΎΡ‚Ρ‹ Ρ‚Π°ΠΊΠΎΠ³ΠΎ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π° Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ прописан Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ Π½ΡƒΠΆΠ½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° Π΄Π°Π½Π½Ρ‹Ρ….
ΠŸΡ€ΠΈ использовании ? Π½Π° Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ Ρ‚ΠΈΠΏΠ° Result<T,E> ΠΈΠ»ΠΈ Option<T>, ошибка Err(e) ΠΈΠ»ΠΈ None Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½Π° Ρ€Π°Π½ΠΎ ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π° Π² случаС успСха - Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π²Π΅Ρ€Π½Ρ‘Ρ‚ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, ΠΈ функция ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, которая Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ послСдний символ 1ΠΎΠΉ строки тСкста:

fn last_char_of_first_line(text: &str) -> Option<char> {
    text.lines().next()?.chars().last()
} // lines() Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ Π½Π° тСкст
  // next() Π±Π΅Ρ€Ρ‘Ρ‚ ΠΏΠ΅Ρ€Π²ΡƒΡŽ строку тСкста. Если тСкст пустой - сразу Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ None

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ошибками

Files

ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ список Ρ„Π°ΠΉΠ»ΠΎΠ²

Ѐункция read_dir:

use std::fs;
fn main() {
    let paths = fs::read_dir("./").unwrap();

    for path in paths {
        println!("{}", path.unwrap().path().display())
    }
}

ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ список Ρ„Π°ΠΉΠ»ΠΎΠ² с ΠΈΡ… Π°Π±ΡΠΎΠ»ΡŽΡ‚Π½Ρ‹ΠΌ ΠΏΡƒΡ‚Ρ‘ΠΌ Π² систСмС

use std::fs;
use std::process;

fn main() {
    let paths = fs::read_dir("./").unwrap();

    for path in paths {
        let pathbuf = path.unwrap().path();
        println!("{:?}", fs::canonicalize(&pathbuf));
    }

    println!("\nPID = {}\n", process::id());
}

Π§Ρ‚Π΅Π½ΠΈΠ΅ тСкста ΠΈΠ· Ρ„Π°ΠΉΠ»ΠΎΠ² Π² строку

Для чтСния Ρ„Π°ΠΉΠ»ΠΎΠ², Π½ΡƒΠΆΠ½ΠΎ сначала Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ нСсколько ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² ΠΈΠ· Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ: FIle - ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΈ Read - Ρ‡Ρ‚Π΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²Ρ…ΠΎΠ΄ΠΈΡ‚ Π² prelude.

se std::fs::File;         // ΠΈΠΌΠΏΠΎΡ€Ρ‚ File
use std::io::prelude::*;  // ΠΈΠΌΠΏΠΎΡ€Ρ‚ Read
  
fn main() {  
    // Ρ‡ΠΈΡ‚Π°Π΅ΠΌΡ‹ΠΉ Ρ„Π°ΠΉΠ» находится Π² ΠΊΠΎΡ€Π½Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°.
    let mut file = File::open("access.log.10").expect("File not opened!");  
  
    let mut contents = String::new(); // Π·Π°ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ» Π² ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ-строку
    file.read_to_string(&mut contents).expect("Cannot read file!");  
  
    println!("File contents: \n\n{}",contents);  
}

Π§Ρ‚Π΅Π½ΠΈΠ΅ Π² Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΈΠ· Π±Π°ΠΉΡ‚ΠΎΠ² (vector of bytes)

Π§Ρ‚Π΅Π½ΠΈΠ΅ Ρ„Π°ΠΉΠ»Π° Π² ΠΏΠ°ΠΌΡΡ‚ΡŒ Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ ΠΊΠ°ΠΊ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° Π±Π°ΠΉΡ‚ΠΎΠ² - для Π±ΠΈΠ½Π°Ρ€Π½Ρ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ², Π»ΠΈΠ±ΠΎ для частого обращСния ΠΊ содСрТимому:

use std::io::Read;
use std::{env, fs, io, str};

fn main() -> io::Result<()> {
    let mut file = fs::File::open("test_file.txt")?;
    let mut contents = Vec::new();
    file.read_to_end(&mut contents);
    println!("File contents: {:?}", contents); // Π²Ρ‹Π²ΠΎΠ΄ Π±Π°ΠΉΡ‚

    let text = match str::from_utf8(&contents) { // ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ Π² строку UTF8
        Ok(v) => v,
        Err(e) => panic!("Invalid UTF-8: {e}"),
    };
    println!("Result: {text}"); // Π²Ρ‹Π²ΠΎΠ΄ строкой
    Ok(())
}

Π§Ρ‚Π΅Π½ΠΈΠ΅ тСкста ΠΈΠ· Ρ„Π°ΠΉΠ»Π° Π² Π±ΡƒΡ„Π΅Ρ€ ΠΏΠΎ строчкам

НуТно Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ΅ File Ρ‚Π°ΠΊΠΆΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ ΠΎΡ€Π³Π°Π½ΠΈΠ·Π°Ρ†ΠΈΠΈ Π±ΡƒΡ„Π΅Ρ€Π° чтСния, Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ ошибки открытия Ρ„Π°ΠΉΠ»Π° ΠΈ чтСния.

use std::io::{BufRead, BufReader};
use std::{env, fs, io};

fn main() -> io::Result<()> {
    let file = fs::File::open("textfile.txt")?;
    let reader = BufReader::new(file);
    
    for line in reader.lines() { // io::BufRead::lines()
        let line = line?;
        println!("{line}");
    }
    Ok(())

Β Π—Π°ΠΏΠΈΡΡŒ Π² Ρ„Π°ΠΉΠ»Ρ‹

use std::fs::File;  
use std::io::prelude::*;  
  
fn main() {  
    let mut file = File::create("report.log").expect("File not created!");  
  
    file.write_all(b"report.log");  
}

Flow Control

IF-ELSE

Π’ Rust Π΅ΡΡ‚ΡŒ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Ρ‡Π΅Ρ€Π΅Π· конструкции IF, ELSE IF, ELSE:

let test_number = 6;

if test_number % 4 == 0 {
println!("Divisible by 4");
} else if test_number % 3 == 0 { // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° останавливаСтся Π½Π° ΠΏΠ΅Ρ€Π²ΠΎΠΌ 
println!("Divisible by 3");      // Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΠΌΠΎΠΌ условии, дальнСйшиС ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ
} else if test_number % 2 == 0 { // ΠΏΡ€ΠΎΠΏΡƒΡΠΊΠ°ΡŽΡ‚ΡΡ.
println!("Divisible by 2");
} else {
println!("Number is not divisible by 4, 3 or 2");
}

ΠšΠΎΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡ IF являСтся Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ (expression), поэтому ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ присваиваниС:

let condition = true;

let number = if condition { "aa" } else { "ab" }; // присваиваниС Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° IF
println!("Number is {number}");

LOOPS

Π’Ρ€ΠΈ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π° ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ†ΠΈΠΊΠ»: Ρ‡Π΅Ρ€Π΅Π· ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€Ρ‹ loop, while, for.

LOOP - организация Π²Π΅Ρ‡Π½Ρ‹Ρ… Ρ†ΠΈΠΊΠ»ΠΎΠ². ΠšΠΎΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡ LOOP являСтся Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ΠΌ (expression), поэтому ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ присваиваниС.

    let mut counter = 0;
    let result = loop {        
        counter += 1;
        if counter == 10 {
            break counter * 2; // Π²Ρ‹Ρ…ΠΎΠ΄ ΠΈΠ· Π²Π΅Ρ‡Π½ΠΎΠ³ΠΎ Ρ†ΠΈΠΊΠ»Π°
        }
    }; // ";" Π½ΡƒΠΆΠ½ΠΎ, Ρ‚.ΠΊ. Π±Ρ‹Π»ΠΎ Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅
    println!("The result is {result}");

Если Π΄Π΅Π»Π°Ρ‚ΡŒ Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ Ρ†ΠΈΠΊΠ»Ρ‹, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠΌΠ΅Ρ‡Π°Ρ‚ΡŒ ΠΈΡ… ΠΌΠ΅Ρ‚ΠΊΠΎΠΉ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΡ‚ΡŒ с break Π½Π° Π½ΡƒΠΆΠ½Ρ‹ΠΉ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ.

    let mut count = 0;
    'counting_up: loop {            // ΠΌΠ΅Ρ‚ΠΊΠ° внСшнСго Ρ†ΠΈΠΊΠ»Π°
        println!("count = {count}");
        let mut remaining = 10;

        loop {
            println!("remaining = {remaining}");
            if remaining == 9 {
                break;
            }
            if count == 2 {
                break 'counting_up;  // goto ΠΌΠ΅Ρ‚ΠΊΠ°
            }
            remaining -= 1;
        }

        count += 1;
    }
    println!("End count = {count}");

WHILE - Ρ†ΠΈΠΊΠ» с условиСм. МоТно Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· loop, Π½ΠΎ с while сильно ΠΊΠΎΡ€ΠΎΡ‡Π΅.

    let mut number = 10;
    while number != 0 {
        println!("{number}!");
        number -= 1;
    }
    println!("Π—ΠΠŸΠ£Π‘Πš!");

FOR - Ρ†ΠΈΠΊΠ» ΠΏΠΎ мноТСствам элСмСнтов. Π’ Ρ‚ΠΎΠΌ числС ΠΌΠΎΠΆΠ½ΠΎ Π·Π°Π΄Π°Ρ‚ΡŒ подмноТСство чисСл.

for i in (1..10).rev() { // .rev() - Π²Ρ‹Π΄Π°Ρ‡Π° подмноТСства Π² ΠΎΠ±Ρ€Π°Ρ‚Π½ΡƒΡŽ сторону
println!("Value: {i}");
}
println!("Π—ΠΠŸΠ£Π‘Πš!");

Generics

Usage

Generics Π½ΡƒΠΆΠ½Ρ‹ для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡΡ‚ΡŒ ΠΎΠ΄ΠΈΠ½ ΠΈ Ρ‚ΠΎΡ‚-ΠΆΠ΅ ΠΊΠΎΠ΄ нСсколько Ρ€Π°Π· для Ρ€Π°Π·Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ² Π΄Π°Π½Π½Ρ‹Ρ…. Π­Ρ‚ΠΎ ΠΎΠ΄ΠΈΠ½ ΠΈΠ· Ρ‚Ρ€Ρ‘Ρ… основных способов экономии Π½Π° ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π΅Π½ΠΈΠΈ ΠΊΠΎΠ΄Π° Π½Π°Ρ€Π°Π²Π½Π΅ с макросами ΠΈ интСрфСйсами traits. ΠŸΡ€ΠΈΠΌΠ΅Ρ€: Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ 2 Π½Π°Π±ΠΎΡ€Π° Π΄Π°Π½Π½Ρ‹Ρ… - массив чисСл, массив символов.

fn largest_i32(n_list: &[i32]) -> &i32 {
    let mut largest_num = &n_list[0];
    for i in n_list {
        if largest_num < i {
            largest_num = i;
        }
    }
    largest_num
}

fn largest_char(n_list: &[char]) -> &char {
    let mut largest_char = &n_list[0];
    for i in n_list {
        if largest_char < i {
            largest_char = i;
        }
    }
    largest_char

ВмСсто Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΈΡΠ°Ρ‚ΡŒ 2 ΠΏΠΎΡ‡Ρ‚ΠΈ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ‡Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΠΎΠ΄ 2 Ρ‚ΠΈΠΏΠ° Π΄Π°Π½Π½Ρ‹Ρ…, ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ ΠΎΠ±Π° Ρ‚ΠΈΠΏΠ° Π² 1 Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, ΡƒΠΊΠ°Π·Π°Π² “Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ”.

Note

НуТно ΡƒΡ‡Π΅ΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ Π½Π΅ всС Ρ‚ΠΈΠΏΡ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠΌΠ΅ΡŽΡ‚ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ сравнСния ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² ΠΌΠ΅ΠΆΠ΄Ρƒ собой, Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Π²Ρ‹ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΠΈΡ… Π² порядок (Order). ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ Π² ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Π½ΠΈΠΆΠ΅ Π½Π°Π΄ΠΎ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ Ρ‚ΠΈΠΏ Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ΅ интСрфСйсом-свойством (trait) порядка.

fn largest_universal<T: std::cmp::PartialOrd>(list: &[T]) -> &T {  
    // <T> = Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ, со свойством упорядочивания PartialOrd
    let mut largest = &list[0];  
  
    for item in list {  
        if largest < item {  
            largest = item;  
        }  
    }  
    largest  
}

fn main() {  
    let num_list = vec![11, 6, 33, 56, 13];//ΡƒΠΏΠΎΡ€ΡΠ΄ΠΎΡ‡ΠΈΡ‚ΡŒ числа 
    println!("Largest number: {}", largest_universal(&num_list));  
  
    let char_list = vec!['y','m','a','q'];//ΡƒΠΏΠΎΡ€ΡΠ΄ΠΎΡ‡ΠΈΡ‚ΡŒ символы Π² Ρ‚ΠΎΠΉ ΠΆΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ  
    println!("Largest char: {}", largest_universal(&char_list));
}

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Ρ‹ с Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΌΠΈ Ρ‚ΠΈΠΏΠ°ΠΌΠΈ

МоТно ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ структуры, Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ… ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Π·Π°Ρ€Π°Π½Π΅Π΅ Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½. ΠŸΡ€ΠΈΡ‡Ρ‘ΠΌ Π² ΠΎΠ΄Π½ΠΎΠΉ структурС ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ нСсколько Ρ€Π°Π·Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ².

struct Point<T,U> {  // <T> ΠΈ <U> - 2 Ρ€Π°Π·Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠ°
    x: T,  
    y: U,  
}

let integer = Point{x:5,y:6};  // Π² ΠΎΠ±Π° поля пишСм числа Ρ‚ΠΈΠΏΠ° i32
let float_int = Point{x:1,y:4.2}; // Π² поля пишСм Ρ€Π°Π·Π½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ i32 ΠΈ f32

Аналогично Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ Π² пСрСчислСниях:

enum Option<T> {
    Some(T), // <T> - Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ любого Ρ‚ΠΈΠΏΠ°, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΈΠ»ΠΈ Π½Π΅Ρ‚
    None,
}

enum Result<T, E> {
    Ok(T), // T - Ρ‚ΠΈΠΏ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ
    Err(E), // Π• - Ρ‚ΠΈΠΏ ошибки
}

ΠœΠ΅Ρ‚ΠΎΠ΄Ρ‹ со структурами с Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΌΠΈ Ρ‚ΠΈΠΏΠ°ΠΌΠΈ

МоТно ΠΏΡ€ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ Π½Π°Π΄ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°. Π’Π°ΠΆΠ½ΠΎ Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈ этом Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠΌΠΎΡ‡ΡŒ компилятору ΠΎΡ‚Π΄Π΅Π»ΠΈΡ‚ΡŒ Π΅Π³ΠΎ ΠΎΡ‚ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° Π΄Π°Π½Π½Ρ‹Ρ…. МоТно ΠΏΡ€ΠΈ этом ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ для ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ² Π΄Π°Π½Π½Ρ‹Ρ…, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, расчёт расстояния Π΄ΠΎ Ρ‚ΠΎΡ‡ΠΊΠΈ ΠΎΡ‚ Ρ†Π΅Π½Ρ‚Ρ€Π° ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для чисСл с ΠΏΠ»Π°Π²Π°ΡŽΡ‰Π΅ΠΉ Ρ‚ΠΎΡ‡ΠΊΠΎΠΉ. Для Π΄Ρ€ΡƒΠ³ΠΈΡ… Ρ‚ΠΈΠΏΠΎΠ² Π΄Π°Π½Π½Ρ‹Ρ… ΠΌΠ΅Ρ‚ΠΎΠ΄ расчёта Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚:

struct Point<T> {  
    x: T,  
    y: T,  
}  
  
impl<T> Point<T> {  // ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ΅
    fn show_x(&self) -> &T {  // ΠΌΠ΅Ρ‚ΠΎΠ΄ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΏΠΎΠ»Π΅ Π΄Π°Π½Π½Ρ‹Ρ…
        &self.x  
    } }

impl Point<f32> {  // ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ float Π² ΠΌΠ΅Ρ‚ΠΎΠ΄Π΅, 
// Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для Π½Π΅Π³ΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ расчёт. Для Π½Π΅-float ΠΌΠ΅Ρ‚ΠΎΠ΄ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ
    fn distance_from_origin(&self) -> f32 {  
        (self.x.powi(2) + self.y.powi(2)).sqrt()  
    } }
  
fn main() {  
    let p = Point{x:5,y:6};  
    println!("P.x = {}",p.show_x()); // Π²Ρ‹Π·ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄Π° для экзСмпляра p
}
Tip

Код с Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΌΠΈ Ρ‚ΠΈΠΏΠ°ΠΌΠΈ Π½Π΅ замСдляСт ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ компилятор ΠΏΡ€ΠΎΡ…ΠΎΠ΄ΠΈΡ‚ ΠΈ подставляСт ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ Π²Π΅Π·Π΄Π΅, Π³Π΄Π΅ Π²ΠΈΠ΄ΠΈΡ‚ generics (“monomorphization” of code).

Hashmaps

Hashmap<K, V>

Π­Ρ‚ΠΎ измСняСмая структура ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ (“dictionary” Π² Python), которая Ρ…Ρ€Π°Π½ΠΈΡ‚ ΠΏΠ°Ρ€Ρ‹ “ΠΊΠ»ΡŽΡ‡->Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅”. Π’ Rust Prelude ΠΎΠ½Π° Π½Π΅ Π²Ρ…ΠΎΠ΄ΠΈΡ‚, макроса создания Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ Π½ΡƒΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ явно ΠΈ явно ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ структуру.

use std::collections::HashMap;  
  
fn main() {  
    let mut scores = HashMap::new();  
    scores.insert(String::from("Alpha"),1);  
    scores.insert(String::from("Beta"),2);  
    scores.insert(String::from("Gamma"),3); 
}

ВсС ΠΊΠ»ΡŽΡ‡ΠΈ Hashmap Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ ΠΈ ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°, всС значСния Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°.

Warning

ЗначСния с ΠΊΡƒΡ‡ΠΈ Ρ‚ΠΈΠΏΠ° String ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π°ΡŽΡ‚ΡΡ (move) Π² Hashmap, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ становится ΠΈΡ… Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π΅ΠΌ.

ВзятиС значСния ΠΏΠΎ ΠΊΠ»ΡŽΡ‡Ρƒ ΠΈΠ· Hashmap с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ get Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠΏΡ€ΠΎΠ²ΠΎΠΆΠ΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΎΠΉ - Π΅ΡΡ‚ΡŒ Π»ΠΈ Π² памяти Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°Π΅ΠΌΡ‹Π΅ ΠΊΠ»ΡŽΡ‡ ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅:

let name = String::from("Gamma");  
if let Some(letter_num) = scores.get(&name) {  
    println!("{}",letter_num);  
} else { println!("Value not in HashMap!"); }

Π˜Ρ‚Π΅Ρ€Π°Ρ†ΠΈΡ ΠΏΠΎ Hashmap ΠΏΠΎΡ…ΠΎΠΆΠ° Π½Π° ΠΈΡ‚Π΅Ρ€Π°Ρ†ΠΈΡŽ ΠΏΠΎ Π²Π΅ΠΊΡ‚ΠΎΡ€Ρƒ:

for (key, value) in &scores {  
    println!("{key} -> {value}"); }

ОбновлСниС Hashmap

Π•ΡΡ‚ΡŒ ряд стратСгий обновлСния Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Π² Hashmap:

  • ΠŸΠ΅Ρ€Π΅Π·Π°ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ всСгда
scores.insert(String::from("Gamma"),3); // вставка Π΄Π²Π°ΠΆΠ΄Ρ‹ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ ΠΏΠΎ ΠΎΠ΄Π½ΠΎΠΌΡƒ 
scores.insert(String::from("Gamma"),6); // ΠΊΠ»ΡŽΡ‡Ρƒ сохранит послСднСС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅
  • Π—Π°ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, Ссли Ρƒ ΠΊΠ»ΡŽΡ‡Π° Π΅Π³ΠΎ Π½Π΅Ρ‚:
scores.entry(String::from("Delta")).or_insert(4); // entry провСряСт Π½Π°Π»ΠΈΡ‡ΠΈΠ΅
// значСния, or_insert Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ mut ссылку Π½Π° Π½Π΅Π³ΠΎ, Π»ΠΈΠ±ΠΎ записываСт Π½ΠΎΠ²ΠΎΠ΅ 
// Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ mut ссылку Π½Π° это Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.
  • Π—Π°ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, Ссли ΠΊΠ»ΡŽΡ‡Π° Π½Π΅Ρ‚. Если ΠΆΠ΅ Ρƒ ΠΊΠ»ΡŽΡ‡Π° Π΅ΡΡ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, ΠΌΠΎΠ΄ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ:
use std::collections::HashMap;

let mut map: HashMap<&str, u32> = HashMap::new();

map.entry("poneyland") // ΠΏΠ΅Ρ€Π²ΠΎΠ΅ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅
   .and_modify(|e| { *e += 1 })
   .or_insert(42);     // Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ ΠΊΠ»ΡŽΡ‡ "poneyland: 42"
assert_eq!(map["poneyland"], 42);

map.entry("poneyland") // Π²Ρ‚ΠΎΡ€ΠΎΠ΅ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π°ΠΉΠ΄Ρ‘Ρ‚ ΠΊΠ»ΡŽΡ‡ со Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ
   .and_modify(|e| { *e += 1 }) // ΠΈ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΡ†ΠΈΡ€ΡƒΠ΅Ρ‚ Π΅Π³ΠΎ
   .or_insert(42);
assert_eq!(map["poneyland"], 43);
  • Π—Π°ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, Ссли ΠΊΠ»ΡŽΡ‡Π° Π½Π΅Ρ‚, Π² Π²ΠΈΠ΄Π΅ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. Π­Ρ‚Π° функция ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ ссылку Π½Π° Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΊΠ»ΡŽΡ‡Π° key, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ пСрСдаётся Π² .entry(key):
use std::collections::HashMap;

let mut map: HashMap<&str, usize> = HashMap::new();
map
  .entry("poneyland")
  .or_insert_with_key(|key| key.chars().count());

assert_eq!(map["poneyland"], 9);
  • ΠŸΠΎΠ΄Π½ΠΈΠΌΠ°Ρ‚ΡŒ староС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΊΠ»ΡŽΡ‡Π°, ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ Π΅Π³ΠΎ ΠΏΠ΅Ρ€Π΅Π΄ ΠΏΠ΅Ρ€Π΅Π·Π°ΠΏΠΈΡΡŒΡŽ:
let text = "hello world wonderful world";  
let mut map = HashMap::new();  
  
for word in text.split_whitespace() {  
    let count = map.entry(word).or_insert(0);  
    *count += 1;  
}  

println!("{:?}",map); // {"wonderful": 1, "hello": 1, "world": 2}

Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ HashMap со значСниями ΠΏΠΎ-ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ

ПовСдСниС Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½ΠΎ Ρ‚ΠΈΠΏΡƒ defaultdict Π² Python. Π—Π°ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ ΠΊΠ»ΡŽΡ‡Π°ΠΌΠΈ HashMap:

  • Π² случаС отсутствия ΠΊΠ»ΡŽΡ‡Π°, ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ Π΅Π³ΠΎ со Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ ΠΏΠΎ-ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ (0);
  • Π² случаС присутствия ΠΊΠ»ΡŽΡ‡Π°, Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ ΠΊ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ +1.
use std::collections::HashMap;
pub fn main() {
    let num_vec = vec![1, 2, 1, 3, 5, 2, 1, 4, 6];
    let mut number_count: HashMap<i32, i32> = HashMap::new();
    for key in num_vec {
        *number_count.entry(key).or_default() += 1;
    }
    for (k, v) in number_count {
        print!("{} -> {}; ", k, v);
    }
}
// 4 -> 1; 1 -> 3; 2 -> 2; 6 -> 1; 5 -> 1; 3 -> 1;

Modules Structure

External link: https://doc.rust-lang.org/stable/book/ch07-02-defining-modules-to-control-scope-and-privacy.html

ΠŸΡ€Π°Π²ΠΈΠ»Π° Ρ€Π°Π±ΠΎΡ‚Ρ‹ с модулями

  • Crate Root. ΠŸΡ€ΠΈ компиляции crate, компилятор ΠΈΡ‰Π΅Ρ‚ ΠΊΠΎΡ€Π΅Π½ΡŒ: src/lib.rs для Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, Π»ΠΈΠ±ΠΎ src/main.rs для запускаСмого Ρ„Π°ΠΉΠ»Π° (binary);
  • ΠœΠΎΠ΄ΡƒΠ»ΠΈ. ΠŸΡ€ΠΈ Π΄Π΅ΠΊΠ»Π°Ρ€ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ модуля Π² crate root, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, mod test, компилятор Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΊΠ°Ρ‚ΡŒ Π΅Π³ΠΎ ΠΊΠΎΠ΄ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΈΠ· мСст:
    • Π‘Ρ€Π°Π·Ρƒ послС объявлСния Π² Ρ‚ΠΎΠΌ ΠΆΠ΅ Ρ„Π°ΠΉΠ»Π΅ (inline);
    • Π’ Ρ„Π°ΠΉΠ»Π΅ src/test.rs;
    • Π’ Ρ„Π°ΠΉΠ» src/test/mod.rs - старый ΡΡ‚ΠΈΠ»ΡŒ, поддСрТиваСтся, Π½ΠΎ Π½Π΅ рСкомСндуСтся.
  • ΠŸΠΎΠ΄ΠΌΠΎΠ΄ΡƒΠ»ΠΈ. Π’ любом Ρ„Π°ΠΉΠ»Π΅, ΠΊΡ€ΠΎΠΌΠ΅ crate root, ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±ΡŠΡΠ²ΠΈΡ‚ΡŒ ΠΏΠΎΠ΄ΠΌΠΎΠ΄ΡƒΠ»ΡŒ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, mod automa. ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ‚ΠΎΡ€ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΊΠ°Ρ‚ΡŒ ΠΊΠΎΠ΄ подмодуля Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΈΠ· мСст:
    • Π‘Ρ€Π°Π·Ρƒ послС объявлСния Π² Ρ‚ΠΎΠΌ ΠΆΠ΅ Ρ„Π°ΠΉΠ»Π΅ (inline);
    • Π’ Ρ„Π°ΠΉΠ»Π΅ src/test/automa.rs;
    • Π’ Ρ„Π°ΠΉΠ»Π΅ src/test/automa/mod.rs - *старый ΡΡ‚ΠΈΠ»ΡŒ, поддСрТиваСтся, Π½ΠΎ Π½Π΅ рСкомСндуСтся.
  • ΠŸΡƒΡ‚ΡŒ Π΄ΠΎ ΠΊΠΎΠ΄Π°. Когда ΠΌΠΎΠ΄ΡƒΠ»ΡŒ Ρ‡Π°ΡΡ‚ΡŒ crate, ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±Ρ€Π°Ρ‰Π°Ρ‚ΡŒΡΡ ΠΊ Π΅Π³ΠΎ ΠΊΠΎΠ΄Ρƒ ΠΈΠ· любого мСста этой crate Π² соотвСтствии с ΠΏΡ€Π°Π²ΠΈΠ»Π°ΠΌΠΈ privacy ΠΈ указывая ΠΏΡƒΡ‚ΡŒ Π΄ΠΎ ΠΊΠΎΠ΄Π°. НапримСр, ΠΏΡƒΡ‚ΡŒ Π΄ΠΎ Ρ‚ΠΈΠΏΠ° robot Π² ΠΏΠΎΠ΄ΠΌΠΎΠ΄ΡƒΠ»Π΅ automa Π±ΡƒΠ΄Π΅Ρ‚ crate::test::automa::robot;
  • Private/public. Код модуля скрыт ΠΎΡ‚ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΈΡ… ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ. Для Π΅Π³ΠΎ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ±ΡŠΡΠ²Π»ΡΡ‚ΡŒ Π΅Π³ΠΎ с pub mod вмСсто mod;
  • Use. ΠšΠ»ΡŽΡ‡Π΅Π²ΠΎΠ΅ слово use Π½ΡƒΠΆΠ½ΠΎ для сокращСния написания ΠΏΡƒΡ‚ΠΈ Π΄ΠΎ ΠΊΠΎΠ΄Π°: use crate::test::automa::robot позволяСт Π΄Π°Π»Π΅Π΅ ΠΏΠΈΡΠ°Ρ‚ΡŒ просто robot для обращСния ΠΊ Π΄Π°Π½Π½Ρ‹ΠΌ этого Ρ‚ΠΈΠΏΠ°.
Note

НуТно лишь Π΅Π΄ΠΈΠ½ΠΎΠΆΠ΄Ρ‹ внСсти внСшний Ρ„Π°ΠΉΠ» с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ mod Π² Π΄Π΅Ρ€Π΅Π²Π΅ ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ стал Ρ‡Π°ΡΡ‚ΡŒΡŽ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°, ΠΈ Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ Ρ„Π°ΠΉΠ»Ρ‹ ΠΌΠΎΠ³Π»ΠΈ Π½Π° Π½Π΅Π³ΠΎ ΡΡΡ‹Π»Π°Ρ‚ΡŒΡΡ. Π’ ΠΊΠ°ΠΆΠ΄ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ mod Π½Π΅ Π½Π°Π΄ΠΎ ΡΡΡ‹Π»Π°Ρ‚ΡŒΡΡ, mod - это НЕ include ΠΈΠ· Python ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΡ… языков программирования.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ структуры

my_crate
β”œβ”€β”€ Cargo.lock
β”œβ”€β”€ Cargo.toml
└── src
    β”œβ”€β”€ test
    β”‚Β Β  └── automa.rs
    β”œβ”€β”€ test.rs
    └── main.rs

Π’Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΌΠΎΠ΄ΡƒΠ»ΠΈ

Для ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°, Π²ΠΎΠ·ΡŒΠΌΡ‘ΠΌ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ, ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΠ²Π°ΡŽΡ‰ΡƒΡŽ Ρ€Π°Π±ΠΎΡ‚Ρƒ рСсторана. РСсторан дСлится Π½Π° части front - обслуТиваниС посСтитСлСй, ΠΈ back - кухня, ΠΌΠΎΠΉΠΊΠ°, бухгалтСрия.

mod front {
    mod hosting {
        fn add_to_waitlist() {}
        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}
        fn serve_order() {}
        fn take_payment() {}
    }
}

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ обращСния ΠΊ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π²Π»ΠΎΠΆΠ΅Π½Π½ΠΎΠ³ΠΎ модуля

ОбъявлСниС модуля ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΌ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ pub Π½Π΅ Π΄Π΅Π»Π°Π΅Ρ‚ Π΅Π³ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΌΠΈ. НуТно ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½ΠΎΡΡ‚ΡŒ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΠΎ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ:

mod front_of_house {
    pub mod hosting { // ΠΌΠΎΠ΄ΡƒΠ»ΡŒ ΠΏΡƒΠ±Π»ΠΈΡ‡Π΅Π½, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊ Π½Π΅ΠΌΡƒ ΠΎΠ±Ρ€Π°Ρ‰Π°Ρ‚ΡŒΡΡ
        pub fn add_to_waitlist() {} // функция явно ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Π°
        // нСсмотря Π½Π° ΠΏΡƒΠ±Π»ΠΈΡ‡Π½ΠΎΡΡ‚ΡŒ модуля, ΠΊ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒΡΡ нСльзя
        // Ссли ΠΎΠ½Π° Π½Π΅ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Π°
    }
}

pub fn eat_at_restaurant() {
    // ΠΠ±ΡΠΎΠ»ΡŽΡ‚Π½Ρ‹ΠΉ ΠΏΡƒΡ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· ΠΊΠΎΡ€Π΅Π½ΡŒ - ΠΊΠ»ΡŽΡ‡Π΅Π²ΠΎΠ΅ слово crate
    crate::front_of_house::hosting::add_to_waitlist();

    // ΠžΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΡƒΡ‚ΡŒ
    front_of_house::hosting::add_to_waitlist();
}

ΠžΠ±Ρ€Π°Ρ‰Π½ΠΈΠ΅ ΠΊ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π²Ρ‹ΡˆΠ΅ ΡƒΡ€ΠΎΠ²Π½Π΅ΠΌ

ΠžΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ Π²Ρ‹Π·ΠΎΠ² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· super (Π°Π½Π°Π»ΠΎΠ³ “..” Π² Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠΉ систСмС):

fn deliver_order() {}

mod back_of_house {
    fn fix_incorrect_order() {
        cook_order();
        super::deliver_order(); // Π²Ρ‹Π·ΠΎΠ² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π² Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠΌ ΠΌΠΎΠ΄ΡƒΠ»Π΅
    }
    fn cook_order() {}
}

ΠžΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ ΠΊ структурам ΠΈ пСрСчислСниям

Поля структур ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ. ΠžΠ±ΠΎΠ·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ структуры ΠΏΡƒΠ±Π»ΠΈΡ‡Π½ΠΎΠΉ с pub Π½Π΅ Π΄Π΅Π»Π°Π΅Ρ‚ Π΅Ρ‘ поля ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΌΠΈ - ΠΊΠ°ΠΆΠ΄ΠΎΠ΅ ΠΏΠΎΠ»Π΅ Π½ΡƒΠΆΠ½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΌ ΠΏΠΎ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ.

mod back_of_house {
    pub struct Breakfast {      // структура ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡Π΅Π½Π° ΠΊΠ°ΠΊ публичная
        pub toast: String,      // ΠΏΠΎΠ»Π΅ ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡Π΅Π½ΠΎ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΌ
        seasonal_fruit: String, // ΠΏΠΎΠ»Π΅ ΠΎΡΡ‚Π°Π»ΠΎΡΡŒ ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ΠΌ
    }

    impl Breakfast {
        pub fn summer(toast: &str) -> Breakfast {
            Breakfast {
                toast: String::from(toast),
                seasonal_fruit: String::from("peaches"),
    } } } }

pub fn eat_at_restaurant() {
    // ΠžΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ ΠΊ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. Π‘Π΅Π· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΊ структурС с ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ΠΌ ΠΏΠΎΠ»Π΅ΠΌ 
    // Π½Π΅ получится ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒΡΡ:
    let mut meal = back_of_house::Breakfast::summer("Rye");
    // запись Π² ΠΏΡƒΠ±Π»ΠΈΡ‡Π½ΠΎΠ΅ ΠΏΠΎΠ»Π΅:
    meal.toast = String::from("Wheat");
    println!("I'd like {} toast please", meal.toast);

    // Ссли Ρ€Π°ΡΠΊΠΎΠΌΠΌΠ΅Π½ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ строку Π΄Π°Π»Π΅Π΅, Π±ΡƒΠ΄Π΅Ρ‚ ошибка компиляции:
    // meal.seasonal_fruit = String::from("blueberries");
}

Поля пСрСчислСний ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ. Достатоно ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ само пСрСчислСниС ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΌ pub enum, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ всС Π΅Π³ΠΎ поля.

mod back_of_house {
    pub enum Appetizer { // ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡Π°Π΅ΠΌ пСрСчислСниС ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΌ
        Soup,
        Salad,
    } }

pub fn eat_at_restaurant() {
    let order1 = back_of_house::Appetizer::Soup;
    let order2 = back_of_house::Appetizer::Salad;
}

ΠžΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ ΠΊ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌ ΠΏΠΎΠ΄ Π΄Ρ€ΡƒΠ³ΠΈΠΌ ΠΈΠΌΠ΅Π½Π΅ΠΌ

Π‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ as ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ярлык Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π² строкС с use. ОсобСнно это ΡƒΠ΄ΠΎΠ±Π½ΠΎ Π² случаС, ΠΊΠΎΠ³Π΄Π° Π½ΡƒΠΆΠ½ΠΎ ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒΡΡ ΠΊ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹ΠΌ ΠΏΠΎ ΠΈΠΌΠ΅Π½ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌ Π² Ρ€Π°Π·Π½Ρ‹Ρ… модулях:

use std::fmt::Result;
use std::io::Result as IoResult; // IoResult - ярлык Π½Π° Ρ‚ΠΈΠΏ Result Π² ΠΌΠΎΠ΄ΡƒΠ»Π΅ io

fn function1() -> Result {
    // ... }

fn function2() -> IoResult<()> {
    // ... }

Π Π΅-экспорт ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ²

ΠŸΡ€ΠΈ ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠΈ ΠΊ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρƒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ use, сам ярлык этот становится ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½Ρ‹ΠΌ - Ρ‡Π΅Ρ€Π΅Π· Π½Π΅Π³ΠΎ ΠΌΠΎΠ³ΡƒΡ‚ ΠΎΠ±Ρ€Π°Ρ‰Π°Ρ‚ΡŒΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ scope. Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ· Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΌΠΎΠ³Π»ΠΈ Ρ‚ΠΎΠΆΠ΅ ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒΡΡ Ρ‡Π΅Ρ€Π΅Π· этот ярлык, Π½ΡƒΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π΅Π³ΠΎ ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΌ:

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    } }

pub use crate::front_of_house::hosting; // Ρ€Π΅-экспорт ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°

pub fn eat_at_restaurant() {
    hosting::add_to_waitlist(); // ΠΎΠ±Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ ΠΊ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Ρ‡Π΅Ρ€Π΅Π· ярлык
}

Π Π°Π±ΠΎΡ‚Π° с внСшними Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌΠΈ

Π’Π½Π΅ΡˆΠ½ΠΈΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Π²ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‚ΡΡ Π² Ρ„Π°ΠΉΠ» Cargo.toml. Π”Π°Π»Π΅Π΅, ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΠΈΠ· Π½ΠΈΡ… заносятся Π² scope с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ use.

# Cargo.toml
rand = "0.8.5"
use rand::Rng;
fn main() {
    let secret_number = rand::thread_rng().gen_range(1..=100);
}

Если Π½ΡƒΠΆΠ½ΠΎ внСсти нСсколько ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² ΠΈΠ· ΠΎΠ΄Π½ΠΎΠΉ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠΊΡ€Π°Ρ‚ΠΈΡ‚ΡŒ количСство use:

//use std::cmp::Ordering;
//use std::io;
use std::{cmp::Ordering, io}; // список ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² ΠΎΡ‚ ΠΎΠ±Ρ‰Π΅Π³ΠΎ корня

//use std::io;
//use std::io::Write;
use std::io{self, Write}; // Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ самого ΠΎΠ±Ρ‰Π΅Π³ΠΎ корня Π² scope

use std::collections::*; // Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ всСх ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² ΠΏΠΎ ΠΏΡƒΡ‚ΠΈ
Warning

Π‘Π»Π΅Π΄ΡƒΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ остороТным с ΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠΌ glob - *, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΏΡ€ΠΎ внСсённыС с Π΅Π³ΠΎ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ слоТно ΡΠΊΠ°Π·Π°Ρ‚ΡŒ, Π³Π΄Π΅ ΠΈΠΌΠ΅Π½Π½ΠΎ ΠΎΠ½ΠΈ Π±Ρ‹Π»ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Ρ‹.

Ownership and References

Ownership

ОбъявлСнная пСрСмСнная, обСспСчСнная ΠΏΠ°ΠΌΡΡ‚ΡŒΡŽ ΠΊΡƒΡ‡ΠΈ (heap) - ΠΎΠ±Ρ‰Π΅ΠΉ ΠΏΠ°ΠΌΡΡ‚ΡŒΡŽ (Π½Π΅ стСка!) всСгда ΠΈΠΌΠ΅Π΅Ρ‚ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π°. ΠŸΡ€ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ Ρ‚Π°ΠΊΠΎΠΉ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ Π² Π΄Ρ€ΡƒΠ³ΡƒΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ, Π»ΠΈΠ±ΠΎ Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, происходит ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ указатСля Π½Π° ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ = смСна Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π°. ПослС пСрСмСщСния, нСльзя ΠΎΠ±Ρ€Π°Ρ‰Π°Ρ‚ΡŒΡΡ ΠΊ исходной ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ.

let s1 = String::from("hello"); // строка Π² ΠΊΡƒΡ‡Π΅ создана ΠΈΠ· Π»ΠΈΡ‚Π΅Ρ€Π°Π»ΠΎΠ² Π² стСкС
let s2 = s1;                    // ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅
println!("{}, world!", s1);     // ошибка! Π’Ρ‹Π·ΠΎΠ² ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Ρ‘Π½Π½ΠΎΠΉ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ

РСшСния:

  • МоТно ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ явный ΠΊΠ»ΠΎΠ½ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ со Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ;
    let s1 = String::from("hello");
    let s2 = s1.clone();                  // ΠΏΠΎΠ»Π½Ρ‹ΠΉ ΠΊΠ»ΠΎΠ½. МСдлСнно ΠΈ Π·Π°Ρ‚Ρ€Π°Ρ‚Π½ΠΎ,
    println!("s1 = {}, s2 = {}", s1, s2); // Π½ΠΎ Π½Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ владСния
  • ΠŸΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ ссылку Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ. Бсылка Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ - ‘&’, Ρ€Π°ΡΠΊΡ€Ρ‹Ρ‚ΡŒ ссылку Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ - ‘*’.
fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);      // ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° ссылки Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ
    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize { // ΠΏΡ€ΠΈΡ‘ΠΌ ссылки Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ
    s.len()
}

References

Для внСсСния ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ ΠΏΠΎ ссылкС Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ, Π½ΡƒΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ это явно Ρ‡Π΅Ρ€Π΅Π· ‘mut’.

fn main() {
    let mut s = String::with_capacity(32); // ΠΎΠ±ΡŠΡΠ²ΠΈΡ‚ΡŒ Ρ€Π°Π·ΠΌΠ΅Ρ€ Π±Π»ΠΎΠΊΠ° Π΄Π°Π½Π½Ρ‹Ρ… Π·Π°Ρ€Π°Π½Π΅Π΅, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΡ‚ΠΎΠΌ Π½Π΅ Π΄ΠΎΠ²Ρ‹Π΄Π΅Π»ΡΡ‚ΡŒ ΠΏΡ€ΠΈ Π·Π°ΠΊΠΈΠ΄Ρ‹Π²Π°Π½ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ… Π² строку = быстрСС
    change(&mut s); // ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° измСняСмой ссылки
}

fn change(some_string: &mut String) { // ΠΏΡ€ΠΈΡ‘ΠΌ измСняСмой ссылки Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ
    some_string.push_str("hello, world");
}
Tip

ΠŸΡ€Π°Π²ΠΈΠ»Π°:

  1. Π’ области ΠΆΠΈΠ·Π½ΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ лишь ΠΎΠ΄Π½Π° измСняСмая ссылка Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ (нСльзя ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ нСскольким ΠΏΠΎΡ‚ΠΎΠΊΠ°ΠΌ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π² ΠΎΠ΄Π½Ρƒ ΠΎΠ±Π»Π°ΡΡ‚ΡŒ памяти);
  2. Если Π΅ΡΡ‚ΡŒ измСняСмая ссылка Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ, Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ нСизмСняСмых ссылок Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ этой ΠΆΠ΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ (ΠΈΠ½Π°Ρ‡Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π·Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π² процСссС ΠΈΡ… ΠΆΠ΅ чтСния);
  3. Если ссылка Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ нСизмСняСмая, ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ сколько ΡƒΠ³ΠΎΠ΄Π½ΠΎ нСизмСняСмых ссылок Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ (ΠΌΠΎΠΆΠ½ΠΎ вмСстС Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΎΠ΄Π½ΠΈ ΠΈ Ρ‚Π΅ ΠΆΠ΅ Π΄Π°Π½Π½Ρ‹Π΅);
  4. ΠšΠΎΠ½Π΅Ρ† ΠΆΠΈΠ·Π½ΠΈ ссылки опрСдСляСтся Π΅Ρ‘ послСдним использованиСм. МоТно ΠΎΠ±ΡŠΡΠ²Π»ΡΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ ссылку Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ, Ссли послСдняя измСняСмая ссылка ΠΏΠΎ Ρ…ΠΎΠ΄Ρƒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π±ΠΎΠ»Π΅Π΅ Π½Π΅ вызываСтся.
let mut s = String::from("hello");
{
    let r1 = &mut s;
} // r1 Π²Ρ‹ΡˆΠ»Π° ΠΈΠ· области ΠΆΠΈΠ·Π½ΠΈ, поэтому ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±ΡŠΡΠ²ΠΈΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ ссылку Π½Π° ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ.
    let r2 = &mut s;

Regular Expressions

Π’Π½Π΅ΡˆΠ½ΡΡ ссылка: https://docs.rs/regex/latest/regex/

Π‘ΠΏΡ€Π°Π²ΠΊΠ° ΠΏΠΎ символам

1 символ

.             any character except new line (includes new line with s flag)
[0-9]         any ASCII digit
\d            digit (\p{Nd})
\D            not digit
\pX           Unicode character class identified by a one-letter name
\p{Greek}     Unicode character class (general category or script)
\PX           Negated Unicode character class identified by a one-letter name
\P{Greek}     negated Unicode character class (general category or script)

ΠšΠ»Π°ΡΡΡ‹ символов

[xyz]         A character class matching either x, y or z (union).
[^xyz]        A character class matching any character except x, y and z.
[a-z]         A character class matching any character in range a-z.
[[:alpha:]]   ASCII character class ([A-Za-z])
[[:^alpha:]]  Negated ASCII character class ([^A-Za-z])
[x[^xyz]]     Nested/grouping character class (matching any character except y and z)
[a-y&&xyz]    Intersection (matching x or y)
[0-9&&[^4]]   Subtraction using intersection and negation (matching 0-9 except 4)
[0-9--4]      Direct subtraction (matching 0-9 except 4)
[a-g~~b-h]    Symmetric difference (matching `a` and `h` only)
[\[\]]        Escaping in character classes (matching [ or ])
[a&&b]        An empty character class matching nothing

ΠŸΠΎΠ²Ρ‚ΠΎΡ€Ρ‹ символов

x*        zero or more of x (greedy)
x+        one or more of x (greedy)
x?        zero or one of x (greedy)
x*?       zero or more of x (ungreedy/lazy)
x+?       one or more of x (ungreedy/lazy)
x??       zero or one of x (ungreedy/lazy)
x{n,m}    at least n x and at most m x (greedy)
x{n,}     at least n x (greedy)
x{n}      exactly n x
x{n,m}?   at least n x and at most m x (ungreedy/lazy)
x{n,}?    at least n x (ungreedy/lazy)
x{n}?     exactly n x

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹

Π—Π°ΠΌΠ΅Π½Π° всСх совпадСний Π² строкС

Π—Π°Π΄Π°Ρ‡Π° Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ строки, Ρ€Π°Π·Π΄Π΅Π»Ρ‘Π½Π½Ρ‹Π΅ - ΠΈΠ»ΠΈ _ Π½Π° CamelCase. ΠŸΡ€ΠΈ этом Ссли строка начинаСтся с Π·Π°Π³Π»Π°Π²Π½ΠΎΠΉ Π±ΡƒΠΊΠ²Ρ‹, Ρ‚ΠΎ ΠΏΠ΅Ρ€Π²ΠΎΠ΅ слово Π½ΠΎΠ²ΠΎΠΉ строки Ρ‚ΠΎΠΆΠ΅ с Π½Π΅Ρ‘ начинаСтся:

"the-stealth-warrior" => "theStealthWarrior"
"The_Stealth_Warrior" => "TheStealthWarrior"
"The_Stealth-Warrior" => "TheStealthWarrior"

РСшСниС:

use regex::Regex;
fn to_camel_case(text: &str) -> String {
    let before = text;
    let re = Regex::new(r"(-|_)(?P<neme>[A-z])").unwrap();
    let after = re.replace_all(before,|captures: &regex::Captures| {
        captures[2].to_uppercase()
    });
    return after.to_string();
}

Strings

Π‘Ρ‚Π°Ρ‚ΡŒΡ ΠΏΠΎ ссылкам Π½Π° ΠΏΠ°ΠΌΡΡ‚ΡŒ Π² Rust

String

Π’ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ… с Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π΅ΠΌ. Π˜ΠΌΠ΅Π΅Ρ‚ измСняСмый Ρ€Π°Π·ΠΌΠ΅Ρ€, нСизвСстный Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚ компиляции. ΠŸΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΠ΅Ρ‚ собой Π²Π΅ΠΊΡ‚ΠΎΡ€Π½ΡƒΡŽ структуру:

pub struct String {
    vec: Vec<u8>;
}

ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ структура содСрТит Vec, это Π·Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° массив памяти, Ρ€Π°Π·ΠΌΠ΅Ρ€ строки size структуры ΠΈ Ρ‘ΠΌΠΊΠΎΡΡ‚ΡŒ capacity (сколько ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊ строкС ΠΏΠ΅Ρ€Π΅Π΄ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ Π²Ρ‹Π΄Π΅Π»Π΅Π½ΠΈΠ΅ΠΌ памяти ΠΏΠΎΠ΄ строку).

&String

Бсылка Π½Π° String. НС ΠΈΠΌΠ΅Π΅Ρ‚ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π°, Ρ€Π°Π·ΠΌΠ΅Ρ€ фиксирован, извСстСн Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚ компиляции.

fn change(mystring: &mut String) {
    if !mystring.ends_with("s") {
        mystring.push_str("s");   // добавляСм "s" Π² ΠΊΠΎΠ½Π΅Ρ† исходной строки
    }

str

Набор символов (Π»ΠΈΡ‚Π΅Ρ€Π°Π»ΠΎΠ²), Ρ€Π°Π·ΠΌΠ΅Ρ‰Ρ‘Π½Π½Ρ‹Ρ… Π½Π° стСкС. НС ΠΈΠΌΠ΅Π΅Ρ‚ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π°, Ρ€Π°Π·ΠΌΠ΅Ρ€ фиксирован, извСстСн Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚ компиляции. МоТно ΠΏΡ€Π΅Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ str Π² String Ρ‡Π΅Ρ€Π΅Π· ΠΏΡ€ΠΈΠ·Π½Π°ΠΊ from:

let text = String::from("TEST"); // "TEST" :str

&str

Бсылка Π½Π° Ρ‡Π°ΡΡ‚ΡŒ, slice ΠΎΡ‚ String (ΠΊΡƒΡ‡Π°), str (стСк) ΠΈΠ»ΠΈ статичСской константы. НС ΠΈΠΌΠ΅Π΅Ρ‚ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π°, Ρ€Π°Π·ΠΌΠ΅Ρ€ фиксирован, извСстСн Π² ΠΌΠΎΠΌΠ΅Π½Ρ‚ компиляции.

  • &String ΠΌΠΎΠΆΠ½ΠΎ нСявно ΠΏΡ€Π΅Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ Π² &str;
  • &str нСльзя нСявно ΠΏΡ€Π΅Π²Ρ€Π°Ρ‰Π°Ρ‚ΡŒ Π² &String.
fn main() {
    let s = "hello_world";
    let mut mut_string = String::from("hello");
    success(&mutable_string);
    fail(s);
}

fn success(data: &str) { // нСявный ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ &String -> &str
    println!("{}", data);
}

fn fail(data: &String) { // ΠžΠ¨Π˜Π‘ΠšΠ - expected &String, but found &str
    println!("{}", data);
}
Warning

Пока сущСствуСт &str Π΅Ρ‘ Π² области ΠΆΠΈΠ·Π½ΠΈ нСльзя ΠΌΠ΅Π½ΡΡ‚ΡŒ содСрТимоС памяти, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΎΠ½Π° ссылаСтся, Π΄Π°ΠΆΠ΅ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π΅ΠΌ строки.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ примСнСния

Π‘Ρ‚Ρ€ΠΎΠΊΠΎΠ²Ρ‹Π΅ константы

const CONST_STRING: &'static str = "a constant string";Β 

ИзмСнСниС строк

ΠŸΡ€ΠΈ Π½Π°Π»ΠΈΡ‡ΠΈΠΈ String, Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ ссылку &mut String для измСнСния:

fn main() {
 let mut mutable_string = String::from("hello ");
 do_mutation(&mut mutable_string);
 println!("{}", mutables_string); // hello world!
}

fn do_mutation(input: &mut String) {
 input.push_str("world!");
}

Π‘Ρ‚Ρ€ΠΎΠΊΠΈ с Π²Π»Π°Π΄Π΅Π½ΠΈΠ΅ΠΌ

ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ String с ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ΠΉ владСния Π½ΡƒΠΆΠ½ΠΎ ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ строки ΠΎΡ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° Π² ΠΏΠΎΡ‚ΠΎΠΊ (thread):

fn main() {
    let s = "hello_world";
    println!("{}", do_upper(s)); // HELLO_WORLD
}

fn do_upper(input: &str) -> String { // Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ String
    input.to_ascii_uppercase()
}

ΠžΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ части строки

ΠŸΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π° Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ, ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘ΠΌ Π² &str:

let s = String::from("Hello World!");
let word = first_word(&s);
println!("The first word is: {}", word);
}

fn first_word(s: &String) -> &str { // ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° строки ΠΏΠΎ ссылкС
let word_count = s.as_bytes();

for (i, &item) in word_count.iter().enumerate() {
    if item == b' ' {
    return &s[..i]; // Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ части строки ΠΊΠ°ΠΊ &str
    }
}
&s[..]  // ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, Ссли условиС Π² Ρ†ΠΈΠΊΠ»Π΅ Π²Ρ‹ΡˆΠ΅ Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ Π²Π΅Ρ€Π½Ρ‘Ρ‚ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, строка Π½Π΅ содСрТит ΠΏΡ€ΠΎΠ±Π΅Π»ΠΎΠ² = Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ всю строку)

МоТно ΠΏΡ€ΠΎΠΉΡ‚ΠΈ ΠΏΠΎ строкС ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ΠΎΠΌ chars() ΠΈ Π΅Π³ΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌΠΈ взятия N-Π³ΠΎ символа nth() спСрСди ΠΈΠ»ΠΈ nth_back() сзади:

let person_name = String::from("Alice");  
println!("The last character of string is: {}", match person_name.chars().nth_back(0) {  // ΠΈΡ‰Π΅ΠΌ 1-Ρ‹ΠΉ символ с ΠΊΠΎΠ½Ρ†Π° строки
        Some(i) => i.to_string(),  // Ссли Π½Π°Ρ…ΠΎΠ΄ΠΈΠΌ - ΠΏΡ€Π΅Π²Ρ€Π°Ρ‰Π°Π΅ΠΌ Π² строку
        None => "Nothing found!".to_string(),  // Π½Π΅ Π½Π°Ρ…ΠΎΠ΄ΠΈΠΌ = сообщаСм
    });  

Π’Ρ‹Π²ΠΎΠ΄ строк

  • ΠœΠ°ΠΊΡ€ΠΎΡ println! позволяСт вывСсти строку Π² ΠΏΠΎΡ‚ΠΎΠΊ stdout;
// println!("Hello there!\n"); 
// раскрываСтся Π² Ρ‚Π°ΠΊΠΎΠΉ ΠΊΠΎΠ΄:
use std::io::{self, Write};
io::stdout().lock().write_all(b"Hello there!\n").unwrap();
  • ΠœΠ°ΠΊΡ€ΠΎΡ format! позволяСт ΡΡ„ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ строку ΠΈ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ;
  • ΠœΠ΅Ρ‚ΠΎΠ΄ len() Π²Ρ‹Π΄Π°Ρ‘Ρ‚ Π΄Π»ΠΈΠ½Ρƒ строки;
  • ΠœΠ΅Ρ‚ΠΎΠ΄ is_empty() провСрят, Ρ‡Ρ‚ΠΎ строка нСпустая;
  • ΠœΠ΅Ρ‚ΠΎΠ΄ contains() ΠΈΡ‰Π΅Ρ‚ ΠΎΠ΄Π½Ρƒ строку Π² Π΄Ρ€ΡƒΠ³ΠΎΠΉ строкС;
  • ΠœΠ΅Ρ‚ΠΎΠ΄ replace(from,to) замСняСт Ρ‡Π°ΡΡ‚ΡŒ строки Π½Π° Π΄Ρ€ΡƒΠ³ΡƒΡŽ ΠΈ Π²Ρ‹Π΄Π°Ρ‘Ρ‚ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚;
  • ΠœΠ΅Ρ‚ΠΎΠ΄ splt_whitespace() позволяСт Π΄Π΅Π»ΠΈΡ‚ΡŒ строку Π½Π° части ΠΏΠΎ ΠΏΡ€ΠΎΠ±Π΅Π»Π°ΠΌ;
  • ΠœΠ΅Ρ‚ΠΎΠ΄ push_str() позволяСт Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ тСкст ΠΊ строкС (строка Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ mut).
fn main() {    
    let mut a = String::from("Wonderful RUST World");  
        println!("Hello{}!", output_string(&a));  // Π²Ρ‹Π²ΠΎΠ΄ строки  
        println!("String is empty? {}", a.is_empty());  
        println!("String length: {}", a.len());  
        println!("Does string contain 'Hello'? {}", a.contains("Hello")); 
        println!("{}",a.replace("RUST","Python")); // Wonderful Python World
  
        for i in a.split_whitespace() {  
            println!("{}", i);  
        }  
      
     a.push_str(" And let's go!");  
     println!("{}",a);
}    
    
fn output_string(t: &String) -> String {  
    format!(", {}",t)   // Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ сформированной строки  
}

ΠŸΠΎΠ²Ρ‚ΠΎΡ€ части строки n Ρ€Π°Π·

Новый ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ std::repeat

fn main() {
    let repeated = "Repeat".repeat(4);
    println!("{}", repeated); // RepeatRepeatRepeatRepeat
} 

Π‘Ρ‚Π°Ρ€Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Ρ‡Π΅Ρ€Π΅Π· ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ - позволяСт бСсконСчно ΠΎΡ‚Π΄Π°Π²Π°Ρ‚ΡŒ любоС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ (ΠΊΠ°ΠΊ generic):

use std::iter;

fn main() {
    let repeated: String = iter::repeat("Repeat").take(4).collect();
    println!("{}", repeated);
}

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Ρ‹

Если структурС Π½Π°Π΄ΠΎ Π²Π»Π°Π΄Π΅Ρ‚ΡŒ своими Π΄Π°Π½Π½Ρ‹ΠΌΠΈ - ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ String. Если Π½Π΅Ρ‚, ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ &str, Π½ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ врСмя ΠΆΠΈΠ·Π½ΠΈ (lifetime), Ρ‡Ρ‚ΠΎΠ±Ρ‹ структура Π½Π΅ ΠΏΠ΅Ρ€Π΅ΠΆΠΈΠ»Π° Π²Π·ΡΡ‚ΡƒΡŽ Π΅ΠΉ строку:

struct Owned {
    bla: String,
}

struct Borrowed<'a> {
    bla: &'a str,
}

fn main() {
    let o = Owned {
        bla: String::from("bla"),
    };
    let b = create_something(&o.bla);
}

fn create_something(other_bla: &str) -> Borrowed {
    let b = Borrowed { bla: other_bla };
    b // ΠΏΡ€ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π΅ Borrowed, пСрСмСнная всё Π΅Ρ‰Ρ‘ Π² области дСйствия!
}

Π Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ строки Π½Π° подстроки

МоТно Π΄Π΅Π»ΠΈΡ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° split(). Π’ Ρ‚ΠΎΠΌ числС ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΏΠΎ нСскольким символам Ρ€Π°Π·ΠΎΠΌ:

    let text = String::from("the_stealth-warrior");
    let parts = text2.split(['-', '_']);
    for part in parts {
        println!("{}", part);

ΠŸΠ΅Ρ€Π²Π°Ρ Π±ΡƒΠΊΠ²Π° Π² строкС

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ ΠΈΠ»ΠΈ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ 1-ΡƒΡŽ Π±ΡƒΠΊΠ²Ρƒ Π² строкС (Π² Ρ‚ΠΎΠΌ числС ΠΈΠ΅Ρ€ΠΎΠ³Π»ΠΈΡ„ ΠΈΠ»ΠΈ ΠΈΠ½ΠΎΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Π°Π»Ρ„Π°Π²ΠΈΡ‚Π°), Π½ΡƒΠΆΠ½ΠΎ строку ΠΏΠ΅Ρ€Π΅Π΄Π΅Π»Π°Ρ‚ΡŒ Π² Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΈΠ· Π±ΡƒΠΊΠ²:

    let char_vec: Vec<char> = text.chars().collect();
    if char_vec[0].is_lowercase() { .. }

ГласныС / согласныС Π±ΡƒΠΊΠ²Ρ‹

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΡƒ Π½ΡƒΠΆΠ½ΠΎ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ Π² Π²ΠΈΠ΄Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ:

fn is_vowel(c: char) -> bool {  
    c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' ||  
    c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U' }

let text = String::from("Aria");

Π Π°Π·Π²ΠΎΡ€ΠΎΡ‚ слов

Π”Π°Π½Π° строка с ΠΏΡ€ΠΎΠ±Π΅Π»Π°ΠΌΠΈ ΠΌΠ΅ΠΆΠ΄Ρƒ словами. НСобходимо Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ слова Π² строкС Π½Π°ΠΎΠ±ΠΎΡ€ΠΎΡ‚, ΠΏΡ€ΠΈ этом ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΏΡ€ΠΎΠ±Π΅Π»Ρ‹.

fn reverse_words_split(str: &str) -> String {  
    str.to_string()
    .split(" ") // ΠΏΡ€ΠΈ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠΈ split() мноТСствСнныС ΠΏΡ€ΠΎΠ±Π΅Π»Ρ‹ ΡΠΎΡ…Ρ€Π°Π½ΡΡŽΡ‚ΡΡ
    .map(|x| x.chars().rev().collect::<String>()) // Ρ€Π°Π·Π²ΠΎΡ€ΠΎΡ‚ слов+сбор Π² строку
    .collect::<Vec<String>>().                    // сбор всСго Π² Π²Π΅ΠΊΡ‚ΠΎΡ€
    .join(" ")                                    // ΠΏΡ€Π΅Π²Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° Π² строку
}

fn main() {  
    let word: &str = "The   quick brown fox jumps over the lazy dog.";  
    println!("{}",reverse_words_split(&word));  
}

// ehT   kciuq nworb xof spmuj revo eht yzal .god

НахоТдСниС закономСрностСй Π² структурах со строками

Π’ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘ΠΌ Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΈΠ· строк. Π”Π°Π»Π΅Π΅, Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Π΅Π³ΠΎ ΠΏΠΎ частям:

fn likes(names: &[&str]) -> String {
    match names {
        [] => "no one likes this".to_string(),
        [a] => format!("{} likes this", a),
        [a, b] => format!("{} and {} like this", a, b),
        [a, b, c] => format!("{}, {} and {} like this", a, b, c),
        [a, b, other @ ..] => format!("{}, {} and {} others like this", a, b, other.len()),
    }
}

Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΠ±Π΅Π»ΠΎΠ² Π² строкС String

Use split(' '), filter out empty entries then re-join by space:

s.trim()
    .split(' ')
    .filter(|s| !s.is_empty())
    .collect::<Vec<_>>()
    .join(" ")

// Using itertools:
use itertools::Itertools;
s.trim().split(' ').filter(|s| !s.is_empty()).join(" ")

// Using split_whitespace, allocating a vector & string
pub fn trim_whitespace_v1(s: &str) -> String {
    let words: Vec<_> = s.split_whitespace().collect();
    words.join(" ")
}

ΠŸΠΎΠΏΡƒΠ»ΡΡ€Π½Ρ‹Π΅ строковыС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹

Structures

Struct Data Type

Struct - комплСксный измСняСмый Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ…, размСщаСтся Π² ΠΊΡƒΡ‡Π΅ (heap), содСрТит Π²Π½ΡƒΡ‚Ρ€ΠΈ сСбя Ρ€Π°Π·Π½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ Π΄Π°Π½Π½Ρ‹Ρ…. Он ΠΏΠΎΡ…ΠΎΠΆ Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆ (tuple), ΠΎΠ΄Π½Π°ΠΊΠΎ Ρ‚ΠΈΠΏΡ‹ Π΄Π°Π½Π½Ρ‹Ρ… Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΈΠΌΠ΅Ρ‚ΡŒ явныС имСнования.

struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64, // запятая Π² ΠΊΠΎΠ½Ρ†Π΅ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Π°
}

МоТно ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‚ΡŒ struct Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ ΠΈΠ»ΠΈ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ:

fn main() {
// создаём измСняяСмый ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΏΠΎ структурС Π΄Π°Π½Π½Ρ‹Ρ… Π²Ρ‹ΡˆΠ΅
let mut user1 = create_user(String::from("john@doe.com"), String::from("testuser")); 

println!("User Email is {}", user1.email);
user1.email = String::from("Parker@doe.com");
println!("User Email is {}", user1.email);
}

fn create_user(email: String, username: String) -> User { // Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ ΠΈΠ· Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ
User {
active: true,
username,  
email,
// ΠΈΠΌΠ΅Π½Π° ΠΏΠΎΠ»Π΅ΠΉ ΠΈΠΌΠ΅ΡŽΡ‚ с Π²Ρ…ΠΎΠ΄Π½Ρ‹ΠΌΠΈ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΌΠΈ, ΠΈ ΠΌΠΎΠΆΠ½ΠΎ Π½Π΅ ΠΏΠΈΡΠ°Ρ‚ΡŒ username: username, email: email.
sign_in_count: 1,
} // return замСняСтся отсутствиСм Π·Π½Π°ΠΊΠ° ";"" ΠΊΠ°ΠΊ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ 
}

Updating Structs

Если Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ структуру ΠΏΠΎ подобию старой, ΠΈ большая Ρ‡Π°ΡΡ‚ΡŒ ΠΏΠΎΠ»Π΅ΠΉ Ρƒ Π½ΠΈΡ… ΠΏΠΎΡ…ΠΎΠΆΠΈ, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ синтаксичСский сахар:

let user2 = User {
email: String::from("another@example.com"), // Π·Π°Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ поля
..user1 // Π²Π·ΡΡ‚ΡŒ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Ρ‹ ΠΈΠ· user1. Π˜Π΄Ρ‘Ρ‚ послСднСй записью
};

Tuple structs

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Ρ‹ Ρ‚Π°ΠΊΠΎΠ³ΠΎ Π²ΠΈΠ΄Π° ΠΏΠΎΡ…ΠΎΠΆΠΈ Π½Π° ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ, Π½ΠΎ ΠΈΠΌΠ΅ΡŽΡ‚ имя структуры ΠΈ Ρ‚ΠΈΠΏ. НуТны, ΠΊΠΎΠ³Π΄Π° Π½ΡƒΠΆΠ½ΠΎ Π²Ρ‹Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΊΠΎΡ€Ρ‚Π΅ΠΆ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΌ Ρ‚ΠΈΠΏΠΎΠΌ, Π»ΠΈΠ±ΠΎ ΠΊΠΎΠ³Π΄Π° Π½Π°Π΄ΠΎ Π΄Π°Ρ‚ΡŒ ΠΎΠ±Ρ‰Π΅Π΅ имя ΠΊΠΎΡ€Ρ‚Π΅ΠΆΡƒ. ΠŸΡ€ΠΈ этом ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ поля Π½Π΅ ΠΈΠΌΠ΅ΡŽΡ‚ ΠΈΠΌΡ‘Π½.

struct Color (i32, i32, i32);
struct Point (i32, i32, i32);

fn main() {
let red = Color(255,0,0);
let origin = Point(0, 0, 0);

ΠŸΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ red ΠΈ origin Ρ€Π°Π·Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ². Π€ΡƒΠ½ΠΊΡ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±Π΅Ρ€ΡƒΡ‚ Color ΠΊΠ°ΠΊ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€, Π½Π΅ Π²ΠΎΠ·ΡŒΠΌΡƒΡ‚ Point, нСсмотря Π½Π° ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ Π²Π½ΡƒΡ‚Ρ€ΠΈ. КаТдая структура = свой собствСнный Ρ‚ΠΈΠΏ. Π Π°Π·Π±ΠΎΡ€ Ρ‚Π°ΠΊΠΈΡ… структур Π½Π° элСмСнты Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π΅Π½ ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠ°ΠΌ.

let (x,y,z) = (origin.0,origin.1,origin.2);

Unit-like structs

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Ρ‹ Π±Π΅Π· ΠΏΠΎΠ»Π΅ΠΉ Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹ ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠ°ΠΌ Π±Π΅Π· ΠΏΠΎΠ»Π΅ΠΉ, Ρ‚ΠΎΠ»ΡŒΠΊΠΎ с ΠΈΠΌΠ΅Π½Π΅ΠΌ.

struct TestTrait;

fn main() {
 test = TestTrait;
}

Π’Π°ΠΊΠΈΠ΅ структуры Π½ΡƒΠΆΠ½Ρ‹ для задания ΠΏΡ€ΠΈΠ·Π½Π°ΠΊΠΎΠ² (traits), ΠΊΠΎΠ³Π΄Π° Π² самой структурС Π΄Π°Π½Π½Ρ‹Π΅ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ.

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π½Ρ‹Π΅ ΠΏΡ€ΠΈΠ·Π½Π°ΠΊΠΈ

МоТно Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΎ содСрТимом ΠΏΠΎΠ»Π΅ΠΉ структуры для Π°Π½Π°Π»ΠΈΠ·Π° ΠΊΠΎΠ΄Π°. Для этого Π½ΡƒΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π½Π°Π΄ структурой ΠΏΠΎΠΌΠ΅Ρ‚ΠΊΡƒ debug:

#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}

fn main() {
  let scale = 2;
  let rect = Rectangle {
  width: dbg!(20 * scale), // Π²Ρ‹Π²ΠΎΠ΄ поля структуры. dbg! Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π½Π°Π·Π°Π΄
  height: 10,              // взятоС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, с Π½ΠΈΠΌ Π΄Π°Π»Π΅Π΅ ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ
  };
  println!("Rectangle content: {:?}",rect); // Π²Ρ‹Π²ΠΎΠ΄ содСрТимого структуры
  dbg!(&rect); // Π΅Ρ‰Ρ‘ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ Π²Ρ‹Π²ΠΎΠ΄Π° - Π² ΠΏΠΎΡ‚ΠΎΠΊ stderr. Ѐункция dbg! 
               // Π·Π°Π±ΠΈΡ€Π°Π΅Ρ‚ Π²Π»Π°Π΄Π΅Π½ΠΈΠ΅ структурой, поэтому ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° ΠΏΠΎ ссылкС
}

Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹

МоТно Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΊΠ°ΠΊ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹, привязанныС ΠΊ структурам. Π­Ρ‚ΠΎ позволяСт ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠ΄ Π±ΠΎΠ»Π΅Π΅ Ρ‡Ρ‘Ρ‚ΠΊΠΎ - ΠΏΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌ ΠΈ дСйствиям Π½Π°Π΄ Π½ΠΈΠΌΠΈ.

struct Rectangle {
width: u32,
height: u32,
}

impl Rectangle {  // impl опрСдСляСт Π±Π»ΠΎΠΊ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² структуры Rectangle
fn area(&self, scale) -> u32 { // 1-Ρ‹ΠΉ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ всСгда self = структура
 self.width * self.height * scale // Ρ‚Π΅Π»ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ значСния
} }

fn main() {
  let rect = Rectangle {
  width: 20,
  height: 10,
  };
  println!("Rectangle area is {}", rect.area(2)); // Π²Ρ‹Π·ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄Π°
}

Как ΠΈ Π²Π΅Π·Π΄Π΅, для внСсСния ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π² ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ структуры, Π² Π±Π»ΠΎΠΊΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±ΡŠΡΠ²ΠΈΡ‚ΡŒ &mut self, Π° для пСрСмСщСния владСния - просто self. Π­Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΠΈΠ·Ρ€Π΅Π΄ΠΊΠ° ΠΏΡ€ΠΈ ΠΏΡ€Π΅Π²Ρ€Π°Ρ‰Π΅Π½ΠΈΠΈ self Π² Π΄Ρ€ΡƒΠ³ΠΎΠΉ Π²ΠΈΠ΄ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°, с Ρ†Π΅Π»ΡŒΡŽ Π·Π°ΠΏΡ€Π΅Ρ‚ΠΈΡ‚ΡŒ Π²Ρ‹Π·ΠΎΠ² ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ вСрсии ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°. Π‘Π»ΠΎΠΊΠΎΠ² impl ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ нСсколько.

АсоциированныС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ

Π’ Π±Π»ΠΎΠΊΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² impl ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠ΅Ρ€Π²Ρ‹ΠΌ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ Π½Π΅ Π±Π΅Ρ€ΡƒΡ‚ саму структуру self. Π’Π°ΠΊΠΈΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π½Π΅ ΡΠ²Π»ΡΡŽΡ‚ΡΡ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌΠΈ ΠΈ часто слуТат для создания Π½ΠΎΠ²Ρ‹Ρ… вСрсий ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°.

fn square(side: u32) -> Self { // Self - алиас для Ρ‚ΠΈΠΏΠ° Π΄Π°Π½Π½Ρ‹Ρ… Rectangle
  Self {
    width: side,
    height: side,
} } }

fn main() {
  let sq = Rectangle::square(10); // Π²Ρ‹Π·ΠΎΠ² асоциированной Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Ρ‡Π΅Ρ€Π΅Π· ::
  println!("Square created from {:?}",sq);
}

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠ° Π΄Π°Π½Π½Ρ‹Ρ… с ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°ΠΌΠΈ

ВмСсто ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ Π²Π²Π΅Π΄Ρ‘Π½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ Π½Π° ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎΡΡ‚ΡŒ Π²Π½ΡƒΡ‚Ρ€ΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±ΡŠΡΠ²ΠΈΡ‚ΡŒ собствСнный Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ…, содСрТащий Π² сСбС всС Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ. НапримСр, объявим число ΠΎΡ‚ 1 Π΄ΠΎ 100 для ΠΈΠ³Ρ€Ρ‹, Π³Π΄Π΅ Π½Π°Π΄ΠΎ ΡƒΠ³Π°Π΄Π°Ρ‚ΡŒ число:

pub struct Guess { // объявили Ρ‚ΠΈΠΏ Π΄Π°Π½Π½Ρ‹Ρ… (ΠΏΡƒΠ±Π»ΠΈΡ‡Π½Ρ‹ΠΉ)
    value: i32,    // Π²Π½ΡƒΡ‚Ρ€ΠΈ число (ΠΏΡ€ΠΈΠ²Π°Ρ‚Π½ΠΎΠ΅)
}

impl Guess {
    pub fn new(value: i32) -> Guess { // ΠΌΠ΅Ρ‚ΠΎΠ΄ new провСряСт Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅
        if value < 1 || value > 100 { // Π½Π° Π·Π°Π΄Π°Π½Π½Ρ‹Π΅ Π³Ρ€Π°Π½ΠΈΡ†Ρ‹ 1-100
            panic!("Guess value must be between 1 and 100, got {}.", value);
        }
        Guess { value } // Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ Π½ΠΎΠ²ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° Π΄Π°Π½Π½Ρ‹Ρ…
    }

    pub fn value(&self) -> i32 { // ΠΌΠ΅Ρ‚ΠΎΠ΄ getter для получСния значСния value
        self.value               // ΠΎΠ½ Π½ΡƒΠΆΠ΅Π½, Ρ‚ΠΊ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ value нСльзя
    }                            // Π­Ρ‚ΠΎ приватная пСрСмСнная Π² структурС.
}

Threads

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅

ΠŸΠΎΡ‚ΠΎΠΊΠΈ - ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ОБ, способ раздСлСния Ρ€Π°Π±ΠΎΡ‚Ρ‹ ПО. На ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² ΠΌΠΎΠ³ΡƒΡ‚ Π½Π°Π·Π½Π°Ρ‡Π°Ρ‚ΡŒΡΡ Ρ€Π°Π·Π½Ρ‹Π΅ ядра, Π° ΠΌΠΎΠ³ΡƒΡ‚ ΠΈ Π½Π΅ Π½Π°Π·Π½Π°Ρ‡Π°Ρ‚ΡŒΡΡ. ΠŸΠΎΡ‚ΠΎΠΊΠΈ Π²Ρ‹Π³ΠΎΠ΄Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ³Π΄Π°, ΠΊΠΎΠ³Π΄Π° ΠΎΠ½ΠΈ Π΄Π°ΡŽΡ‚ Π²Ρ‹ΠΈΠ³Ρ€Ρ‹Ρˆ Π²ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ большС, Ρ‡Π΅ΠΌ врСмя Π½Π° ΠΈΡ… созданиС (Π½Π° x86 процСссорах = ~9000 наносСк, Π½Π° ARM процСссорах = ~27000 наносСк). ΠžΠ±Ρ‹Ρ‡Π½ΠΎ, это интСнсивныС ΠΏΠΎ вычислСниям прилоТСния. Для интСнсивным ΠΏΠΎ Π²Π²ΠΎΠ΄Ρƒ-Π²Ρ‹Π²ΠΎΠ΄Ρƒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ слСдуСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ async/await вмСсто ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ².

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ создания:

fn hello_thread() {
    println!("Hello from thread")
}

fn main() {
    println!("Hello from the MAIN thread");

    let thread_handle = std::thread::spawn(hello_thread);
    thread_handle.join().unwrap(); // Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ Π½ΠΎΠ²Ρ‹ΠΉ ΠΏΠΎΡ‚ΠΎΠΊ с Π³Π»Π°Π²Π½Ρ‹ΠΌ
    // ΠΏΠΎΡ‚ΠΎΠΊΠΎΠΌ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹, ΠΈΠ½Π°Ρ‡Π΅ ΠΎΠ½ ΠΌΠΎΠΆΠ΅Ρ‚ Π½Π΅ ΡƒΡΠΏΠ΅Ρ‚ΡŒ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π΄ΠΎ
    // Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ Π³Π»Π°Π²Π½ΠΎΠ³ΠΎ ΠΏΠΎΡ‚ΠΎΠΊΠ° ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹
}

ΠŸΠΎΡ‚ΠΎΠΊΠΈ ΡΠ²Π»ΡΡŽΡ‚ΡΡ Π²Π»Π°Π΄Π΅Π»ΡŒΡ†Π°ΠΌΠΈ Π΄Π°Π½Π½Ρ‹Ρ…, поэтому Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈΠΌ Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Ρ‰Π΅Π½ΠΈΠ΅ΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ΠΈ Π±Ρ‹Π»ΠΈ ΠΆΠΈΠ²Ρ‹ ΠΊ ΠΌΠΎΠΌΠ΅Π½Ρ‚Ρƒ запуска ΠΏΠΎΡ‚ΠΎΠΊΠ°:

fn do_math(i: u32) -> u32 {
    let mut n = i + 1;
    for _ in 0..10 {
        n *= 2;
    }
    n
}

fn main() {
    println!("Hello from the MAIN thread");

    let mut thread_handles = Vec::new(); // Π²Π΅ΠΊΡ‚ΠΎΡ€ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΉ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²
    for i in 0..10 {
        let thread_handle = std::thread::spawn(move || do_math(i));
        thread_handles.push(thread_handle); // Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΠΎΡ‚ΠΎΠΊ ΠΊ Π²Π΅ΠΊΡ‚ΠΎΡ€
    }
    for h in thread_handles.into_iter() {
        println!("{}", h.join().unwrap()); // соСдинСниС ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² с Π³Π»Π°Π²Π½Ρ‹ΠΌ.
    }                                // ΠΈ Π²Ρ‹Π²ΠΎΠ΄ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΠΎΡ‚ΠΎΠΊΠ°. 

Π Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Π·Π°Π΄Π°Ρ‡ΠΈ Π½Π° ΠΏΠΎΡ‚ΠΎΠΊΠΈ

ΠŸΡ€ΠΎΡΡ‚ΠΎΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ - ΠΏΠΎΠ΄Π΅Π»ΠΈΡ‚ΡŒ Π²Π΅ΠΊΡ‚ΠΎΡ€ со значСниями Π½Π° куски (chunks), ΠΈ ΠΏΠΎΠ΄ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ куска ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠΎΡ‚ΠΎΠΊ, послС Ρ‡Π΅Π³ΠΎ ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ ΠΏΠΎΡ‚ΠΎΠΊΠΈ вмСстС:

fn main() {
    const N_THREADS: usize = 8;
    let to_add = (0..5000).collect::<Vec<u32>>(); // Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΎΡ‚ 0 Π΄ΠΎ 4999
    let mut thread_handles = Vec::new(); // Π²Π΅ΠΊΡ‚ΠΎΡ€ ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΉ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²
    let chunks = to_add.chunks(N_THREADS); // Ρ€Π°Π·ΠΌΠ΅Ρ€ кусков разбиСния

    for chunk in chunks {
        let my_chunk = chunk.to_owned(); // ΠΎΠ±Ρ…ΠΎΠ΄ borrow checker/lifetime
        thread_handles.push(std::thread::spawn(move || my_chunk.iter().sum::<u32>())); // созданиС ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² с ΠΏΡ€ΠΈΠ½Π°Π΄Π»Π΅ΠΆΠ°Ρ‰ΠΈΠΌΠΈ ΠΈΠΌ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ
    }

    // суммированиС ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²-кусков Π² ΠΎΠ΄Π½ΠΎ число
    let mut sum: u32 = 0;
    for handle in thread_handles {
        sum += handle.join().unwrap()
    }
    println!("Sum is {sum}");
}

Traits

Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ Ρ‚ΠΈΠΏΠ°ΠΆΠ°

Π’ΠΈΠΏΠ°ΠΆ Π½ΡƒΠΆΠ΅Π½ для ΠΎΡ€Π³Π°Π½ΠΈΠ·Π°Ρ†ΠΈΠΈ интСрфСйса: ΠΎΠ½ Π·Π°Π΄Π°Ρ‘Ρ‚ ограничСния-особСнности повСдСния для ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… ΠΈΠ»ΠΈ структур с Π½Π΅ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΌΠΈ (generic) ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΌΠΈ. ΠœΡ‹ отдСляСм объявлСниС Ρ‚ΠΈΠΏΠ°ΠΆΠ° ΠΎΡ‚ Π΅Π³ΠΎ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ. ΠŸΡ€ΠΈ объявлСнии Ρ‚ΠΈΠΏΠ°ΠΆΠ° ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΡƒΡŽ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ Π½Π° ΠΏΠΎΡ‚ΠΎΠΌ, Π»ΠΈΠ±ΠΎ Π²ΠΏΠΈΡΠ°Ρ‚ΡŒ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ Π² Ρ‚ΠΈΠΏΠ°ΠΆΠ΅ ΠΏΠΎ-ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ:

// Ρ‚ΠΈΠΏΠ°ΠΆ Π·Π°Π΄Π°Ρ‘Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΈ ограничСния ΠΏΠΎ Π²Ρ…ΠΎΠ΄Π½Ρ‹ΠΌ/Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹ΠΌ Ρ‚ΠΈΠΏΠ°ΠΌ
trait LandVehicle {  
    fn LandDrive(&self) -> String; }  

// Ρ‚ΠΈΠΏΠ°ΠΆ Π·Π°Π΄Π°Ρ‘Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ плюс ΠΈΡ… рСализация ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
trait WaterVehicle {  
    fn WaterDrive(&self) { println!("Default float"); }  
}

ΠŸΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠ°ΠΆΠ΅ΠΉ ΠΊ структурам Π΄Π°Π½Π½Ρ‹Ρ…

Π’ΠΎ врСмя примСнСния, Ссли рСализация ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π±Ρ‹Π»Π° Π·Π°Π΄Π°Π½Π°, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π΅Ρ‘ ΠΏΠ΅Ρ€Π΅Π΄Π΅Π»Π°Ρ‚ΡŒ ΠΏΠΎΠ΄ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΡƒΡŽ структуру, Π»ΠΈΠ±ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ эту Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ:

struct Sedan {}  
struct Rocketship {}  

// Ρ‚ΠΈΠΏΠ°ΠΆ LandVehicle Π½Π΅ ΠΈΠΌΠ΅Π΅Ρ‚ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ Ρ‚ΡƒΡ‚
impl LandVehicle for Sedan {  
    fn LandDrive(&self) -> String { format!("Car zoom-zoom!") } }

// Ρ‚ΠΈΠΏΠ°ΠΆ WaterVehicle ΠΈΠΌΠ΅Π΅Ρ‚ Π²Ρ‹ΡˆΠ΅ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π΅Ρ‘
impl WaterVehicle for Rocketship {}

ОбъСдинСниС Ρ‚ΠΈΠΏΠ°ΠΆΠ΅ΠΉ

ΠŸΡ€ΠΈ объСдинСнии, создаётся ярлык (alias). ΠŸΡ€ΠΈ этом ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ входящий Π² Π½Π΅Π³ΠΎ Ρ‚ΠΈΠΏΠ°ΠΆ Π½ΡƒΠΆΠ½ΠΎ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΊ структурС Π΄Π°Π½Π½Ρ‹Ρ…. ΠŸΡ€ΠΈ этом ΠΌΠΎΠΆΠ½ΠΎ Ρ‚Π°ΠΊΠΆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹Ρ… Π² Ρ‚ΠΈΠΏΠ°ΠΆΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, Π»ΠΈΠ±ΠΎ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ свою.

// созданиС ярлыка
trait AmphibiousVehicle: LandVehicle + WaterVehicle {}

// ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠ°ΠΆΠ΅ΠΉ ΠΊ структурС
impl AmphibiousVehicle for Carrier {}  
impl LandVehicle for Carrier {  
    fn LandDrive(&self) -> String { format!("Use air thrust to travel on land") }  
}  
impl WaterVehicle for Carrier {}

Π’Ρ‹Π·ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² экзСмпляра структуры ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°ΠΆΠ°

fn main() {  
    let toyota_camry = Sedan {};  
    println!("{}",toyota_camry.LandDrive());
  
    let rs = Rocketship {};  
    rs.WaterDrive();  
  
    let project_x = Carrier {};  
    println!("{}",project_x.LandDrive());  
    project_x.WaterDrive();  
}

Variables and constants

Note

When in doubt on variable type: just use i32 for everything! i32 is the default in Rust, and the fastest, even on x64 architecture.

Scalar Types

Unsigned Signed
u8 i8
u16 i16
u32 i32
u64 i64
u128 i128
usize isize
Floating point vars: f32, f64.

You can declare number variables with _ sign in any place for convenience:

let x: i32 = 1_000_000;
let (mut missiles: i32, ready: u32) = (8, 5); // 2 vars tuple assign in 1 line

You can also add the var type to the number (convenient with _ when using generics):

let x = 1000_u32;
let y = 3.14_f32;

Converting

String2Int:

let n_str = "123456789".to_string();
let n_int = n_str.parse::<i32>().unwrap();

Char2Int:

let letter = 'a';
println!("{}", letter as u32 - 96); // = 97-96 = 1
let i = 97u8; // Ρ‚ΠΎΠ»ΡŒΠΊΠΎ с u8 Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ 'as char'
println!("Value: {}", i as char);

Boolean type

bool type can be true or false. Non-integer - do NOT try to use arithmetic on these. But you can cast them:

true as u8;
false as u8;

Mutablitity

By default, variables in Rust are immutable. To make a variable mutable, special “mut” identifier must be placed. Rust compiler may infer the variable type from the type of value.

let x = 5; // immutable variable, type i32 guessed by Rust as default for numbers.

let mut x = 5; // mutable variable

Shadowing

Variable names can be reused. This is not mutability, because shadowing always re-creates the variable from scratch. Previous variable value may be used:

let x = 5; 
let x = x + 1; // new variable created with value = 6

Constants

Constant values are always immutable and available in the scope they were created in throughout the whole program. Type of constant must always be defined. Constants may contain results of operations. They are evaluated by Rust compiler. List of evaluations: https://doc.rust-lang.org/stable/reference/const_eval.html

const ONE_DAY_IN_SECONDS: u32 = 24 * 60 * 60; // type u32 MUST be defined

let phrase = "Hello World";
println!("Before: {phrase}"); // Before: Hello World

let phrase = phrase.len();
println!("After: {phrase}"); // After: 11

Compound variables

Tuple

Compound type, immutable, consists of different types.

let tup: (u32, f32, i32) = (10, 1.2, -32);
let (x,y,z) = tup; // tuple deconstructing into variables
let a1 = tup.0;
let a2 = tup.1; // another way to deconstruct values

Deconstructing tuples is very useful when a function returns a tuple:

let (left, right) = slice.split_at(middle);
let (_, right) = slice.split_at(middle); // use '_' to throw away part of return

Array

Compound type, mutable, all values of the same type.

let ar: [i32;5] = [1,2,3,4,5]; 
// array data is allocated on the stack rather than the heap
// [i32;5] - type of values and number of elements
let first = ar[0]; 
let second = ar[1]; // accessing array elements

ΠŸΠΎΠ΄ΡΡ‡Ρ‘Ρ‚ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Ρ… элСмСнтов Π² массивС с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ itertools…

Vectors

Vectors

Π’Π΅ΠΊΡ‚ΠΎΡ€ - мноТСство Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΠ΄Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°, количСство ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΌΠΎΠΆΠ½ΠΎ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ: Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ ΠΈ ΡƒΠ΄Π°Π»ΡΡ‚ΡŒ элСмСнты. НуТСн, ΠΊΠΎΠ³Π΄Π°:

  • трСбуСтся ΡΠΎΠ±Ρ€Π°Ρ‚ΡŒ Π½Π°Π±ΠΎΡ€ элСмСнтов для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π² Π΄Ρ€ΡƒΠ³ΠΈΡ… мСстах;
  • Π½ΡƒΠΆΠ½ΠΎ Π²Ρ‹ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ элСмСнты Π² ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½ΠΎΠΌ порядкС, с Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ΠΌ Π½ΠΎΠ²Ρ‹Ρ… элСмСнтов Π² ΠΊΠΎΠ½Π΅Ρ†;
  • Π½ΡƒΠΆΠ½ΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ стэк;
  • Π½ΡƒΠΆΠ΅Π½ массив измСняСмой Π²Π΅Π»ΠΈΡ‡ΠΈΠ½Ρ‹ ΠΈ располоТСнный Π² ΠΊΡƒΡ‡Π΅.

ΠœΠ΅Ρ‚ΠΎΠ΄Ρ‹

// Π—Π°Π΄Π°Π½ΠΈΠ΅ пустого Π²Π΅ΠΊΡ‚ΠΎΡ€Π°:
// let mut a test_vector: Vec<i32> = Vec::new();  

// Π—Π°Π΄Π°Π½ΠΈΠ΅ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° со значСниями Ρ‡Π΅Ρ€Π΅Π· макрос:
let mut test_vector = vec![1, 2, 3, 4];  

test_vector.push(42);  // Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ число 42 Π² ΠΊΠΎΠ½Π΅Ρ† mut Π²Π΅ΠΊΡ‚ΠΎΡ€Π°
test_vector.remove(0);  // ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт =1
  
for i in &mut test_vector {  // ΠΏΡ€ΠΎΠΉΡ‚ΠΈ Π²Π΅ΠΊΡ‚ΠΎΡ€ ΠΊΠ°ΠΊ ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€ для Π²Ρ‹Π²ΠΎΠ΄Π°
*i += 1; // ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ значСния ΠΏΡ€ΠΈ ΠΈΡ… ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Π΄Π΅Π»Π°Ρ‚ΡŒ '*' dereference
println!("{i}"); }

println!("Vector length: {}", test_vector.len()); // количСство элСмСнтов

ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ элСмСнта Π²Π΅ΠΊΡ‚ΠΎΡ€Π°

Π­Π»Π΅ΠΌΠ΅Π½Ρ‚ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ индСкса, Π»ΠΈΠ±ΠΎ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° get:

let mut test_vector = vec![1,2,3,4,5];  
  
println!("Third element of vector is: {}", &test_vector[2]);  // индСкс
  
let third: Option<&i32> = test_vector.get(2);  // ΠΌΠ΅Ρ‚ΠΎΠ΄ get
match third {  
    Some(third) => println!("Third element of vector is: {}", third),  
    None => println!("There is no third element")  
}

Π Π°Π·Π½ΠΈΡ†Π° Π² способах Π² Ρ€Π΅Π°ΠΊΡ†ΠΈΠΈ Π½Π° ΠΏΠΎΠΏΡ‹Ρ‚ΠΊΡƒ Π²Π·ΡΡ‚ΡŒ Π½Π΅ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ элСмСнт Π·Π° ΠΏΡ€Π΅Π΄Π΅Π»Π°ΠΌΠΈ Π²Π΅ΠΊΡ‚ΠΎΡ€Π°. ВзятиС Ρ‡Π΅Ρ€Π΅Π· индСкс ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Ρ‚ ΠΊ ΠΏΠ°Π½ΠΈΠΊΠ΅ ΠΈ остановкС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹. ВзятиС с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ get сопровоТдаСтся ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΎΠΉ ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΎΠΉ ошибки.

Π₯Ρ€Π°Π½Π΅Π½ΠΈΠ΅ элСмСнтов Ρ€Π°Π·Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ² Π² Π²Π΅ΠΊΡ‚ΠΎΡ€Π΅

Rust Π½ΡƒΠΆΠ½ΠΎ Π·Π°Ρ€Π°Π½Π΅Π΅ Π·Π½Π°Ρ‚ΡŒ ΠΏΡ€ΠΈ компиляции, сколько Π½ΡƒΠΆΠ½ΠΎ Π²Ρ‹Π΄Π΅Π»ΡΡ‚ΡŒ памяти ΠΏΠΎΠ΄ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ элСмСнт. Если извСстны Π·Π°Ρ€Π°Π½Π΅Π΅ всС Ρ‚ΠΈΠΏΡ‹ для хранСния, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½Ρ‹ΠΉ enum:

#[derive(Debug)]  
enum SpreadSheet {  
    Int(i32),  
    Float(f64),  
    Text(String)  
}  
  
fn main() {  
    let row = vec![  
      SpreadSheet::Int(42),  
      SpreadSheet::Float(3.14),  
      SpreadSheet::Text(String::from("red"))  
    ];  
  
    for i in row {  
        println!("{:?}",i);  
    }  }

Vector со строками String

let mut v: Vec<String> = Vec::new();

ΠŸΡƒΡΡ‚ΠΎΠΉ Π²Π΅ΠΊΡ‚ΠΎΡ€ с Π½ΡƒΠ»Π΅Π²Ρ‹ΠΌΠΈ строками ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· Default Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠΌ Π΄ΠΎ 32 элСмСнтов (Rust 1.47):

let v: [String; 32] = Default::default();

Π’Π΅ΠΊΡ‚ΠΎΡ€ большСго Ρ€Π°Π·ΠΌΠ΅Ρ€Π° ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ Vec:

let mut v: Vec<String> = vec![String::new(); 100];

Π’Π΅ΠΊΡ‚ΠΎΡ€ с Π·Π°Π΄Π°Π½Π½Ρ‹ΠΌΠΈ строками ΠΌΠΎΠΆΠ½ΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π»ΠΈΠ±ΠΎ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠ΅Ρ‚ΠΎΠ΄Π° to_string(), Π»ΠΈΠ±ΠΎ Ρ‡Π΅Ρ€Π΅Π· ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ макроса:

macro_rules! vec_of_strings {
    ($($x:expr),*) => (vec![$($x.to_string()),*]);
}

fn main()
{
    let a = vec_of_strings!["a", "b", "c"];
    let b = vec!["a".to_string(), "b".to_string(), "c".to_string()];
    assert!(a==b); // True
}

Π‘ΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° со строками Π² строку (Join):

result_vec.join(" "); // указываСтся Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ для соСдинСния
// Π² старых вСрсиях Rust <1.3 ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡŽΡ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ .connect();

Π‘ΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²ΠΊΠ°

let number_vector = vec!(1,12,3,1,5);   
number_vector.sort(); // 1,1,3,5,12

Бпособы рСвСрс-сортировки

Π‘ΠΌΠ΅Π½Π° элСмСнтов ΠΏΡ€ΠΈ сравнСнии:

number_vector.sort_by(|a,b| b.cmp(a));

Π‘ΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²ΠΊΠ°, ΠΏΠΎΡ‚ΠΎΠΌ рСвСрс:

number_vector.sort();
number_vector.reverse();

ΠžΠ±Ρ‘Ρ€Ρ‚ΠΊΠ° Reverse с экзСмпляром Ord:

use std::cmp::Reverse;
number_vector.sort_by_key(|w| Reverse(*w));

Если Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ Reverse со ссылкой ΠΈ Π±Π΅Π· *, это ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Ρ‚ ΠΊ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ΅ с Π²Ρ€Π΅ΠΌΠ΅Π½Π΅ΠΌ ΠΆΠΈΠ·Π½ΠΈ.

ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ Π²Π΅ΠΊΡ‚ΠΎΡ€Π° ΠΈΠ· ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€Π°

    let collected_iterator: Vec<i32> = (0..10).collect();
    println!("Collected (0..10) into: {:?}", collected_iterator);
    // Collected (0..10) into: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ΠšΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΡ

ΠšΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΡ ΠΈΠ· массива array Π² vector:

let number_list = [1,12,3,1,5,2];  
let number_vector = number_list.to_vec(); // ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ array[i32] -> vector<i32>

Π’Π°Ρ€ΠΈΠ°Π½Ρ‚ Ρ‡Π΅Ρ€Π΅Π· ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€:

let a = [10, 20, 30, 40]; 
let v: Vec<i32> = a.iter().map(|&e| e as i32).collect(); 

Π’Π΅ΠΊΡ‚ΠΎΡ€ ΠΈΠ· Π±Π°ΠΉΡ‚ΠΎΠ² vector of bytes Π² строку String:

use std::str;

fn main() {
    let buf = &[0x41u8, 0x41u8, 0x42u8]; // vector of bytes
    let s = match str::from_utf8(buf) {
        Ok(v) => v,
        Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
    };
    println!("result: {}", s);
}