├── libtest.rmeta ├── tests └── skeptic.rs ├── assets └── graph.png ├── theme ├── favicon.png ├── css │ └── print.css └── highlight.css ├── src ├── css │ ├── summary.jpg │ └── custom.css ├── main.rs ├── science.md ├── net │ ├── server.md │ └── server │ │ └── listen-unused.md ├── cli │ ├── arguments.md │ ├── ansi_terminal.md │ └── ansi_terminal │ │ └── ansi_term-basic.md ├── hardware │ ├── processor.md │ └── processor │ │ └── cpu-count.md ├── mem │ ├── global_static.md │ └── global_static │ │ └── lazy-constant.md ├── cryptography │ ├── encryption.md │ ├── hashing.md │ └── hashing │ │ ├── hmac.md │ │ └── sha-digest.md ├── data_structures │ ├── bitfield.md │ └── bitfield │ │ └── bitfield.md ├── web │ ├── mime.md │ ├── clients │ │ ├── requests.md │ │ ├── download.md │ │ ├── apis.md │ │ ├── api │ │ │ ├── rest-get.md │ │ │ └── rest-head.md │ │ └── download │ │ │ └── post-file.md │ ├── scraping.md │ ├── url.md │ ├── url │ │ ├── fragment.md │ │ ├── parse.md │ │ ├── new.md │ │ ├── base.md │ │ └── origin.md │ ├── mime │ │ ├── string.md │ │ └── filename.md │ └── scraping │ │ └── extract-links.md ├── science │ └── mathematics │ │ ├── miscellaneous.md │ │ ├── statistics.md │ │ ├── trigonometry.md │ │ ├── complex_numbers.md │ │ ├── trigonometry │ │ ├── tan-sin-cos.md │ │ └── side-length.md │ │ ├── linear_algebra.md │ │ ├── complex_numbers │ │ ├── add-complex.md │ │ ├── create-complex.md │ │ └── mathematical-functions.md │ │ ├── miscellaneous │ │ └── big-integers.md │ │ ├── linear_algebra │ │ ├── multiply-matrices.md │ │ ├── invert-matrix.md │ │ ├── add-matrices.md │ │ ├── deserialize-matrix.md │ │ ├── multiply-scalar-vector-matrix.md │ │ ├── vector-comparison.md │ │ └── vector-norm.md │ │ └── statistics │ │ └── standard-deviation.md ├── errors │ ├── handle.md │ └── handle │ │ └── main.md ├── text │ ├── string_parsing.md │ ├── regex.md │ ├── string_parsing │ │ ├── graphemes.md │ │ └── from_str.md │ └── regex │ │ ├── email.md │ │ ├── hashtags.md │ │ ├── replace.md │ │ └── filter-log.md ├── encoding │ ├── complex.md │ ├── strings.md │ ├── csv.md │ ├── csv │ │ ├── delimiter.md │ │ ├── invalid.md │ │ ├── serde-serialize.md │ │ ├── serialize.md │ │ └── filter.md │ ├── string │ │ ├── base64.md │ │ ├── hex.md │ │ ├── url-encode.md │ │ └── percent-encode.md │ └── complex │ │ ├── endian-byte.md │ │ ├── json.md │ │ └── toml.md ├── file │ ├── read-write.md │ ├── dir.md │ ├── dir │ │ ├── png.md │ │ ├── duplicate-name.md │ │ ├── sizes.md │ │ ├── find-file.md │ │ ├── ignore-case.md │ │ ├── skip-dot.md │ │ └── loops.md │ └── read-write │ │ ├── memmap.md │ │ ├── same-file.md │ │ └── read-file.md ├── algorithms │ ├── sorting.md │ ├── randomness.md │ ├── sorting │ │ ├── sort.md │ │ ├── sort_float.md │ │ └── sort_struct.md │ └── randomness │ │ ├── rand-passwd.md │ │ ├── rand.md │ │ ├── rand-choose.md │ │ ├── rand-custom.md │ │ ├── rand-range.md │ │ └── rand-dist.md ├── datetime │ ├── duration.md │ ├── parse.md │ ├── duration │ │ ├── profile.md │ │ ├── timezone.md │ │ └── checked.md │ └── parse │ │ ├── format.md │ │ ├── current.md │ │ └── timestamp.md ├── compression │ ├── tar.md │ └── tar │ │ ├── tar-decompress.md │ │ ├── tar-compress.md │ │ └── tar-strip-prefix.md ├── database │ ├── sqlite.md │ ├── postgres.md │ ├── sqlite │ │ ├── initialization.md │ │ └── transactions.md │ └── postgres │ │ ├── create_tables.md │ │ ├── aggregate_data.md │ │ └── insert_query_data.md ├── net.md ├── data_structures.md ├── development_tools │ ├── debugging │ │ ├── log.md │ │ ├── config_log.md │ │ ├── log │ │ │ ├── log-error.md │ │ │ ├── log-stdout.md │ │ │ ├── log-debug.md │ │ │ ├── log-syslog.md │ │ │ └── log-custom-logger.md │ │ └── config_log │ │ │ ├── log-env-variable.md │ │ │ ├── log-mod.md │ │ │ ├── log-custom.md │ │ │ └── log-timestamp.md │ ├── versioning.md │ ├── build_tools.md │ ├── versioning │ │ ├── semver-prerelease.md │ │ ├── semver-complex.md │ │ ├── semver-increment.md │ │ └── semver-latest.md │ └── build_tools │ │ ├── cc-bundled-cpp.md │ │ └── cc-defines.md ├── hardware.md ├── mem.md ├── os │ ├── external.md │ └── external │ │ ├── read-env-variable.md │ │ ├── error-file.md │ │ ├── continuous.md │ │ ├── send-input.md │ │ ├── process-output.md │ │ └── piped.md ├── concurrency │ ├── threads.md │ ├── parallel.md │ ├── parallel │ │ ├── rayon-iter-mut.md │ │ ├── rayon-parallel-sort.md │ │ ├── rayon-parallel-search.md │ │ ├── rayon-any-all.md │ │ └── rayon-map-reduce.md │ └── thread │ │ ├── crossbeam-spawn.md │ │ ├── crossbeam-spsc.md │ │ └── global-mut-state.md ├── cli.md ├── compression.md ├── errors.md ├── cryptography.md ├── database.md ├── os.md ├── datetime.md ├── text.md ├── algorithms.md └── development_tools.md ├── .gitignore ├── .editorconfig ├── .gitattributes ├── book.toml ├── LICENSE-MIT └── Cargo.toml /libtest.rmeta: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/skeptic.rs: -------------------------------------------------------------------------------- 1 | include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs")); 2 | -------------------------------------------------------------------------------- /assets/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzy/rust-cookbook-zh-cn/HEAD/assets/graph.png -------------------------------------------------------------------------------- /theme/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzy/rust-cookbook-zh-cn/HEAD/theme/favicon.png -------------------------------------------------------------------------------- /src/css/summary.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zzy/rust-cookbook-zh-cn/HEAD/src/css/summary.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Cargo.lock 3 | target/ 4 | *~ 5 | book/ 6 | *.swp 7 | lines.txt 8 | .idea/ 9 | 10 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("This program does nothing."); 3 | println!("See documentation at https://github.com/rust-lang-nursery/rust-cookbook"); 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.toml] 8 | indent_style = space 9 | indent_size = 2 10 | 11 | [*.rs] 12 | indent_style = space 13 | indent_size = 4 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-language=Rust 2 | 3 | *.md linguist-detectable=true 4 | docs/* linguist-documentation 5 | 6 | * text=auto eol=lf 7 | 8 | *.{cmd,[cC][mM][dD]} text eol=crlf 9 | *.{bat,[bB][aA][tT]} text eol=crlf 10 | -------------------------------------------------------------------------------- /src/science.md: -------------------------------------------------------------------------------- 1 | # 科学计算 2 | 3 | 8 | 9 | {{#include science/mathematics.md}} 10 | 11 | {{#include links.md}} 12 | -------------------------------------------------------------------------------- /src/net/server.md: -------------------------------------------------------------------------------- 1 | # 服务器 2 | 3 | 8 | 9 | {{#include server/listen-unused.md}} 10 | 11 | {{#include ../links.md}} 12 | -------------------------------------------------------------------------------- /src/cli/arguments.md: -------------------------------------------------------------------------------- 1 | # 参数解析 2 | 3 | 8 | 9 | {{#include arguments/clap-basic.md}} 10 | 11 | {{#include ../links.md}} 12 | -------------------------------------------------------------------------------- /src/hardware/processor.md: -------------------------------------------------------------------------------- 1 | # 处理器 2 | 3 | 8 | 9 | {{#include processor/cpu-count.md}} 10 | 11 | {{#include ../links.md}} 12 | -------------------------------------------------------------------------------- /src/mem/global_static.md: -------------------------------------------------------------------------------- 1 | # 常量 2 | 3 | 8 | 9 | {{#include global_static/lazy-constant.md}} 10 | 11 | {{#include ../links.md}} 12 | -------------------------------------------------------------------------------- /src/cli/ansi_terminal.md: -------------------------------------------------------------------------------- 1 | # ANSI 终端 2 | 3 | 8 | 9 | {{#include ansi_terminal/ansi_term-basic.md}} 10 | 11 | {{#include ../links.md}} 12 | -------------------------------------------------------------------------------- /src/cryptography/encryption.md: -------------------------------------------------------------------------------- 1 | # 加密 2 | 3 | 8 | 9 | {{#include encryption/pbkdf2.md}} 10 | 11 | {{#include ../links.md}} 12 | -------------------------------------------------------------------------------- /src/data_structures/bitfield.md: -------------------------------------------------------------------------------- 1 | # 位域 2 | 3 | 8 | 9 | {{#include bitfield/bitfield.md}} 10 | 11 | {{#include ../links.md}} 12 | -------------------------------------------------------------------------------- /src/web/mime.md: -------------------------------------------------------------------------------- 1 | # 媒介类型 2 | 3 | 8 | 9 | {{#include mime/string.md}} 10 | 11 | {{#include mime/filename.md}} 12 | 13 | {{#include mime/request.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /src/cryptography/hashing.md: -------------------------------------------------------------------------------- 1 | # 散列(哈希) 2 | 3 | 8 | 9 | {{#include hashing/sha-digest.md}} 10 | 11 | {{#include hashing/hmac.md}} 12 | 13 | {{#include ../links.md}} 14 | -------------------------------------------------------------------------------- /src/web/clients/requests.md: -------------------------------------------------------------------------------- 1 | # 请求处理 2 | 3 | 8 | 9 | {{#include requests/get.md}} 10 | 11 | {{#include requests/header.md}} 12 | 13 | {{#include ../../links.md}} 14 | -------------------------------------------------------------------------------- /src/science/mathematics/miscellaneous.md: -------------------------------------------------------------------------------- 1 | # 其它数学计算 2 | 3 | 8 | 9 | {{#include miscellaneous/big-integers.md}} 10 | 11 | {{#include ../../links.md}} -------------------------------------------------------------------------------- /src/errors/handle.md: -------------------------------------------------------------------------------- 1 | # 处理错误变量 2 | 3 | 8 | 9 | {{#include handle/main.md}} 10 | 11 | {{#include handle/retain.md}} 12 | 13 | {{#include handle/backtrace.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /src/text/string_parsing.md: -------------------------------------------------------------------------------- 1 | # 字符串解析 2 | 3 | 8 | 9 | {{#include string_parsing/graphemes.md}} 10 | 11 | {{#include string_parsing/from_str.md}} 12 | 13 | {{#include ../links.md}} 14 | -------------------------------------------------------------------------------- /src/web/scraping.md: -------------------------------------------------------------------------------- 1 | # 提取链接 2 | 3 | 8 | 9 | {{#include scraping/extract-links.md}} 10 | 11 | {{#include scraping/broken.md}} 12 | 13 | {{#include scraping/unique.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /src/encoding/complex.md: -------------------------------------------------------------------------------- 1 | # 结构化数据 2 | 3 | 8 | 9 | {{#include complex/json.md}} 10 | 11 | {{#include complex/toml.md}} 12 | 13 | {{#include complex/endian-byte.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /src/file/read-write.md: -------------------------------------------------------------------------------- 1 | # 文件读写 2 | 3 | 8 | 9 | {{#include read-write/read-file.md}} 10 | 11 | {{#include read-write/same-file.md}} 12 | 13 | {{#include read-write/memmap.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /src/algorithms/sorting.md: -------------------------------------------------------------------------------- 1 | # Vector 排序 2 | 3 | 8 | 9 | {{#include sorting/sort.md}} 10 | {{#include sorting/sort_float.md}} 11 | {{#include sorting/sort_struct.md}} 12 | 13 | {{#include ../links.md}} 14 | -------------------------------------------------------------------------------- /src/datetime/duration.md: -------------------------------------------------------------------------------- 1 | # 期间和计算 2 | 3 | 8 | 9 | {{#include duration/profile.md}} 10 | 11 | {{#include duration/checked.md}} 12 | 13 | {{#include duration/timezone.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /src/compression/tar.md: -------------------------------------------------------------------------------- 1 | # 使用 tar 包 2 | 3 | 8 | 9 | {{#include tar/tar-decompress.md}} 10 | 11 | {{#include tar/tar-compress.md}} 12 | 13 | {{#include tar/tar-strip-prefix.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /src/database/sqlite.md: -------------------------------------------------------------------------------- 1 | # SQLite 2 | 3 | 8 | 9 | {{#include sqlite/initialization.md}} 10 | 11 | {{#include sqlite/insert_select.md}} 12 | 13 | {{#include sqlite/transactions.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /src/web/clients/download.md: -------------------------------------------------------------------------------- 1 | # 下载 2 | 3 | 8 | 9 | {{#include download/basic.md}} 10 | 11 | {{#include download/partial.md}} 12 | 13 | {{#include download/post-file.md}} 14 | 15 | {{#include ../../links.md}} 16 | -------------------------------------------------------------------------------- /src/science/mathematics/statistics.md: -------------------------------------------------------------------------------- 1 | # 统计学 2 | 3 | 8 | 9 | {{#include statistics/central-tendency.md}} 10 | {{#include statistics/standard-deviation.md}} 11 | 12 | 13 | {{#include ../../links.md}} 14 | -------------------------------------------------------------------------------- /src/datetime/parse.md: -------------------------------------------------------------------------------- 1 | # 解析与显示 2 | 3 | 8 | 9 | {{#include parse/current.md}} 10 | 11 | {{#include parse/timestamp.md}} 12 | 13 | {{#include parse/format.md}} 14 | 15 | {{#include parse/string.md}} 16 | 17 | {{#include ../links.md}} 18 | -------------------------------------------------------------------------------- /src/web/url.md: -------------------------------------------------------------------------------- 1 | # URL 2 | 3 | 8 | 9 | {{#include url/parse.md}} 10 | 11 | {{#include url/base.md}} 12 | 13 | {{#include url/new.md}} 14 | 15 | {{#include url/origin.md}} 16 | 17 | {{#include url/fragment.md}} 18 | 19 | {{#include ../links.md}} 20 | -------------------------------------------------------------------------------- /src/database/postgres.md: -------------------------------------------------------------------------------- 1 | # 使用 Postgres 2 | 3 | 8 | 9 | {{#include postgres/create_tables.md}} 10 | 11 | {{#include postgres/insert_query_data.md}} 12 | 13 | {{#include postgres/aggregate_data.md}} 14 | 15 | {{#include ../links.md}} 16 | -------------------------------------------------------------------------------- /src/encoding/strings.md: -------------------------------------------------------------------------------- 1 | # 字符集 2 | 3 | 8 | 9 | {{#include string/percent-encode.md}} 10 | 11 | {{#include string/url-encode.md}} 12 | 13 | {{#include string/hex.md}} 14 | 15 | {{#include string/base64.md}} 16 | 17 | {{#include ../links.md}} 18 | -------------------------------------------------------------------------------- /src/text/regex.md: -------------------------------------------------------------------------------- 1 | # 正则表达式 2 | 3 | 8 | 9 | {{#include regex/email.md}} 10 | 11 | {{#include regex/hashtags.md}} 12 | 13 | {{#include regex/phone.md}} 14 | 15 | {{#include regex/filter-log.md}} 16 | 17 | {{#include regex/replace.md}} 18 | 19 | {{#include ../links.md}} 20 | -------------------------------------------------------------------------------- /src/science/mathematics/trigonometry.md: -------------------------------------------------------------------------------- 1 | # 三角学 2 | 3 | 8 | 9 | {{#include trigonometry/side-length.md}} 10 | {{#include trigonometry/tan-sin-cos.md}} 11 | {{#include trigonometry/latitude-longitude.md}} 12 | 13 | {{#include ../../links.md}} 14 | -------------------------------------------------------------------------------- /src/net.md: -------------------------------------------------------------------------------- 1 | # 网络 2 | 3 | 8 | 9 | ## 服务器 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [监听未使用的 TCP/IP 端口][ex-random-port-tcp] | [![std-badge]][std] | [![cat-net-badge]][cat-net] | 14 | 15 | [ex-random-port-tcp]: net/server.md#监听未使用的-tcpip-端口 16 | 17 | {{#include links.md}} 18 | -------------------------------------------------------------------------------- /src/web/clients/apis.md: -------------------------------------------------------------------------------- 1 | # Web API 调用 2 | 3 | 8 | 9 | {{#include api/rest-get.md}} 10 | 11 | {{#include api/rest-head.md}} 12 | 13 | {{#include api/rest-post.md}} 14 | 15 | {{#include api/paginated.md}} 16 | 17 | {{#include api/rate-limited.md}} 18 | 19 | {{#include ../../links.md}} 20 | -------------------------------------------------------------------------------- /src/science/mathematics/complex_numbers.md: -------------------------------------------------------------------------------- 1 | # 复数 2 | 3 | 8 | 9 | {{#include complex_numbers/create-complex.md}} 10 | {{#include complex_numbers/add-complex.md}} 11 | {{#include complex_numbers/mathematical-functions.md}} 12 | 13 | {{#include ../../links.md}} 14 | -------------------------------------------------------------------------------- /src/data_structures.md: -------------------------------------------------------------------------------- 1 | # 数据结构 2 | 3 | 8 | 9 | ## 位域 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [定义并操作位域风格的类型][ex-bitflags] | [![bitflags-badge]][bitflags] | [![cat-no-std-badge]][cat-no-std] | 14 | 15 | [ex-bitflags]: data_structures/bitfield.md#定义并操作位域风格的类型 16 | 17 | {{#include links.md}} 18 | -------------------------------------------------------------------------------- /src/development_tools/debugging/log.md: -------------------------------------------------------------------------------- 1 | # 日志信息 2 | 3 | 8 | 9 | {{#include log/log-debug.md}} 10 | 11 | {{#include log/log-error.md}} 12 | 13 | {{#include log/log-stdout.md}} 14 | 15 | {{#include log/log-custom-logger.md}} 16 | 17 | {{#include log/log-syslog.md}} 18 | 19 | {{#include ../../links.md}} 20 | -------------------------------------------------------------------------------- /src/hardware.md: -------------------------------------------------------------------------------- 1 | # 硬件支持 2 | 3 | 8 | 9 | ## 处理器 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [检查逻辑 cpu 内核的数量][ex-check-cpu-cores] | [![num_cpus-badge]][num_cpus] | [![cat-hardware-support-badge]][cat-hardware-support] | 14 | 15 | [ex-check-cpu-cores]: hardware/processor.md#检查逻辑-cpu-内核的数量 16 | 17 | {{#include links.md}} 18 | -------------------------------------------------------------------------------- /src/development_tools/debugging/config_log.md: -------------------------------------------------------------------------------- 1 | # 日志配置 2 | 3 | 8 | 9 | {{#include config_log/log-mod.md}} 10 | 11 | {{#include config_log/log-env-variable.md}} 12 | 13 | {{#include config_log/log-timestamp.md}} 14 | 15 | {{#include config_log/log-custom.md}} 16 | 17 | {{#include ../../links.md}} 18 | -------------------------------------------------------------------------------- /src/mem.md: -------------------------------------------------------------------------------- 1 | # 内存管理 2 | 3 | 8 | 9 | ## 常量 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [声明延迟计算常量][ex-lazy-constant] | [![lazy_static-badge]][lazy_static] | [![cat-caching-badge]][cat-caching] [![cat-rust-patterns-badge]][cat-rust-patterns] | 14 | 15 | [ex-lazy-constant]: mem/global_static.md#声明延迟计算常量 16 | 17 | {{#include links.md}} 18 | -------------------------------------------------------------------------------- /src/encoding/csv.md: -------------------------------------------------------------------------------- 1 | # CSV 处理 2 | 3 | 8 | 9 | {{#include csv/read.md}} 10 | 11 | {{#include csv/delimiter.md}} 12 | 13 | {{#include csv/filter.md}} 14 | 15 | {{#include csv/invalid.md}} 16 | 17 | {{#include csv/serialize.md}} 18 | 19 | {{#include csv/serde-serialize.md}} 20 | 21 | {{#include csv/transform.md}} 22 | 23 | {{#include ../links.md}} 24 | -------------------------------------------------------------------------------- /src/os/external.md: -------------------------------------------------------------------------------- 1 | # 外部命令 2 | 3 | 8 | 9 | {{#include external/process-output.md}} 10 | 11 | {{#include external/send-input.md}} 12 | 13 | {{#include external/piped.md}} 14 | 15 | {{#include external/error-file.md}} 16 | 17 | {{#include external/continuous.md}} 18 | 19 | {{#include external/read-env-variable.md}} 20 | 21 | {{#include ../links.md}} 22 | -------------------------------------------------------------------------------- /src/file/dir.md: -------------------------------------------------------------------------------- 1 | # 目录遍历 2 | 3 | 8 | 9 | {{#include dir/modified.md}} 10 | 11 | {{#include dir/loops.md}} 12 | 13 | {{#include dir/duplicate-name.md}} 14 | 15 | {{#include dir/find-file.md}} 16 | 17 | {{#include dir/skip-dot.md}} 18 | 19 | {{#include dir/sizes.md}} 20 | 21 | {{#include dir/png.md}} 22 | 23 | {{#include dir/ignore-case.md}} 24 | 25 | {{#include ../links.md}} 26 | -------------------------------------------------------------------------------- /src/hardware/processor/cpu-count.md: -------------------------------------------------------------------------------- 1 | ## 检查逻辑 cpu 内核的数量 2 | 3 | 8 | 9 | [![num_cpus-badge]][num_cpus] [![cat-hardware-support-badge]][cat-hardware-support] 10 | 11 | 使用 [`num_cpus::get`] 显示当前机器中的逻辑 CPU 内核的数量。 12 | 13 | ```rust,edition2018 14 | fn main() { 15 | println!("Number of logical cores is {}", num_cpus::get()); 16 | } 17 | ``` 18 | -------------------------------------------------------------------------------- /src/development_tools/versioning.md: -------------------------------------------------------------------------------- 1 | # 版本控制 2 | 3 | 8 | 9 | {{#include versioning/semver-increment.md}} 10 | 11 | {{#include versioning/semver-complex.md}} 12 | 13 | {{#include versioning/semver-prerelease.md}} 14 | 15 | {{#include versioning/semver-latest.md}} 16 | 17 | {{#include versioning/semver-command.md}} 18 | 19 | {{#include ../links.md}} 20 | -------------------------------------------------------------------------------- /src/algorithms/randomness.md: -------------------------------------------------------------------------------- 1 | # 生成随机值 2 | 3 | 8 | 9 | {{#include randomness/rand.md}} 10 | 11 | {{#include randomness/rand-range.md}} 12 | 13 | {{#include randomness/rand-dist.md}} 14 | 15 | {{#include randomness/rand-custom.md}} 16 | 17 | {{#include randomness/rand-passwd.md}} 18 | 19 | {{#include randomness/rand-choose.md}} 20 | 21 | {{#include ../links.md}} 22 | -------------------------------------------------------------------------------- /src/concurrency/threads.md: -------------------------------------------------------------------------------- 1 | # 显式线程 2 | 3 | 8 | 9 | {{#include thread/crossbeam-spawn.md}} 10 | 11 | {{#include thread/crossbeam-complex.md}} 12 | 13 | {{#include thread/crossbeam-spsc.md}} 14 | 15 | {{#include thread/global-mut-state.md}} 16 | 17 | {{#include thread/threadpool-walk.md}} 18 | 19 | {{#include thread/threadpool-fractal.md}} 20 | 21 | {{#include ../links.md}} 22 | -------------------------------------------------------------------------------- /src/concurrency/parallel.md: -------------------------------------------------------------------------------- 1 | # 数据并行 2 | 3 | 8 | 9 | {{#include parallel/rayon-iter-mut.md}} 10 | 11 | {{#include parallel/rayon-any-all.md}} 12 | 13 | {{#include parallel/rayon-parallel-search.md}} 14 | 15 | {{#include parallel/rayon-parallel-sort.md}} 16 | 17 | {{#include parallel/rayon-map-reduce.md}} 18 | 19 | {{#include parallel/rayon-thumbnails.md}} 20 | 21 | {{#include ../links.md}} 22 | -------------------------------------------------------------------------------- /src/css/custom.css: -------------------------------------------------------------------------------- 1 | table { 2 | width: 100%; 3 | } 4 | 5 | table td:first-child { 6 | width: 65%; 7 | } 8 | 9 | table td:nth-child(2) { 10 | width: 20%; 11 | padding: 3px; 12 | } 13 | 14 | table td:nth-child(3) { 15 | padding: 3px; 16 | } 17 | 18 | /* underline hyperlinked inline code items */ 19 | a:hover > .hljs { 20 | text-decoration: underline; 21 | } 22 | 23 | /* color hyperlinked inline code items 24 | identically to normal links */ 25 | .rust a > .hljs, 26 | .navy a > .hljs, 27 | .coal a > .hljs{ 28 | color: #2b79a2; 29 | } 30 | 31 | .light a > .hljs { 32 | color: #4183c4; 33 | } 34 | -------------------------------------------------------------------------------- /src/science/mathematics/trigonometry/tan-sin-cos.md: -------------------------------------------------------------------------------- 1 | ## 验证正切(tan)等于正弦(sin)除以余弦(cos) 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-science-badge]][cat-science] 10 | 11 | 验证 tan(x) 是否等于 sin(x)/cos(x),其中 x=6。 12 | 13 | ```rust,edition2018 14 | fn main() { 15 | let x: f64 = 6.0; 16 | 17 | let a = x.tan(); 18 | let b = x.sin() / x.cos(); 19 | 20 | assert_eq!(a, b); 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /src/science/mathematics/trigonometry/side-length.md: -------------------------------------------------------------------------------- 1 | ## 计算三角形的边长 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-science-badge]][cat-science] 10 | 11 | 计算直角三角形斜边的长度,其中斜边的角度为 2 弧度,对边长度为 80。 12 | 13 | ```rust,edition2018 14 | fn main() { 15 | let angle: f64 = 2.0; 16 | let side_length = 80.0; 17 | 18 | let hypotenuse = side_length / angle.sin(); 19 | 20 | println!("Hypotenuse: {}", hypotenuse); 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /src/science/mathematics/linear_algebra.md: -------------------------------------------------------------------------------- 1 | # 线性代数 2 | 3 | 8 | 9 | {{#include linear_algebra/add-matrices.md}} 10 | {{#include linear_algebra/multiply-matrices.md}} 11 | {{#include linear_algebra/multiply-scalar-vector-matrix.md}} 12 | {{#include linear_algebra/vector-comparison.md}} 13 | {{#include linear_algebra/vector-norm.md}} 14 | {{#include linear_algebra/invert-matrix.md}} 15 | {{#include linear_algebra/deserialize-matrix.md}} 16 | 17 | {{#include ../../links.md}} 18 | -------------------------------------------------------------------------------- /src/cli.md: -------------------------------------------------------------------------------- 1 | # 命令行 2 | 3 | 8 | 9 | ## 参数解析 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [解析命令行参数][ex-clap-basic] | [![clap-badge]][clap] | [![cat-command-line-badge]][cat-command-line] | 14 | 15 | ## ANSI 终端 16 | 17 | | 实例名称 | Crates | 类别 | 18 | |--------|--------|------------| 19 | | [ANSI 终端][ex-ansi_term-basic] | [![ansi_term-badge]][ansi_term]| [![cat-command-line-badge]][cat-command-line] | 20 | 21 | [ex-clap-basic]: cli/arguments.md#解析命令行参数 22 | 23 | [ex-ansi_term-basic]: cli/ansi_terminal.md#ansi-终端 24 | 25 | {{#include links.md}} 26 | -------------------------------------------------------------------------------- /src/science/mathematics/complex_numbers/add-complex.md: -------------------------------------------------------------------------------- 1 | ## 复数相加 2 | 3 | 8 | 9 | [![num-badge]][num] [![cat-science-badge]][cat-science] 10 | 11 | 对复数执行数学运算与对内置类型执行数学运算是一样的:计算的数字必须是相同的类型(如浮点数或整数)。 12 | 13 | ```rust,edition2018 14 | fn main() { 15 | let complex_num1 = num::complex::Complex::new(10.0, 20.0); // 必须为浮点数 16 | let complex_num2 = num::complex::Complex::new(3.1, -4.2); 17 | 18 | let sum = complex_num1 + complex_num2; 19 | 20 | println!("Sum: {}", sum); 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /src/development_tools/build_tools.md: -------------------------------------------------------------------------------- 1 | # 构建工具 2 | 3 | 8 | 9 | 本节介绍在编译 crate 源代码之前运行的“构建时”工具或代码。按照惯例,构建时代码存放在 **build.rs** 文件,通常称为“构建脚本”。常见的用例包括:Rust 代码生成、绑定的 C/C++/asm 代码的编译。要获取更多信息,请阅读 Cargo([中文文档](https://cargo.budshome.com)) 的[构建脚本文档][build-script-docs]。 10 | 11 | {{#include build_tools/cc-bundled-static.md}} 12 | 13 | {{#include build_tools/cc-bundled-cpp.md}} 14 | 15 | {{#include build_tools/cc-defines.md}} 16 | 17 | {{#include ../links.md}} 18 | 19 | [build-script-docs]: https://cargo.budshome.com/reference/build-scripts.html 20 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | title = "Rust Cookbook 中文版 - A Rust Cookbook" 3 | authors = ["zzy"] 4 | language = "zh" 5 | description = "rust cookbook 中文版, Rust 实践指南, Rust 实例示例, Rust 编程实战, Rust crate 生态实践, Rust crate 集成应用" 6 | src = "src" 7 | multilingual = true 8 | 9 | # [build] 10 | # build-dir = "docs" 11 | 12 | [output.html] 13 | theme = "theme" 14 | # default-theme = "rust" 15 | git-repository-url = "https://github.com/zzy/rust-cookbook-zh-cn" 16 | curly-quotes = true 17 | mathjax-support = true 18 | 19 | [output.html.playpen] 20 | editable = true 21 | copy-js = true 22 | 23 | [output.html.search] 24 | limit-results = 20 25 | use-boolean-and = true 26 | boost-title = 2 27 | boost-hierarchy = 2 28 | boost-paragraph = 1 29 | expand = true 30 | heading-split-level = 3 31 | copy-js = true 32 | -------------------------------------------------------------------------------- /src/algorithms/sorting/sort.md: -------------------------------------------------------------------------------- 1 | ## 整数 Vector 排序 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-science-badge]][cat-science] 10 | 11 | 这个实例通过 [`vec::sort`] 对一个整数 Vector 进行排序。另一种方法是使用 [`vec::sort_unstable`],后者运行速度更快一些,但不保持相等元素的顺序。 12 | 13 | ```rust,edition2018 14 | fn main() { 15 | let mut vec = vec![1, 5, 10, 2, 15]; 16 | 17 | vec.sort(); 18 | 19 | assert_eq!(vec, vec![1, 2, 5, 10, 15]); 20 | } 21 | ``` 22 | 23 | [`vec::sort`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort 24 | [`vec::sort_unstable`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort_unstable 25 | -------------------------------------------------------------------------------- /src/concurrency/parallel/rayon-iter-mut.md: -------------------------------------------------------------------------------- 1 | ## 并行改变数组中元素 2 | 3 | 8 | 9 | [![rayon-badge]][rayon] [![cat-concurrency-badge]][cat-concurrency] 10 | 11 | 下面的实例使用了 `rayon` crate,这是一个 Rust 程序设计语言的数据并行库。`rayon` 为任何并行可迭代的数据类型提供 [`par_iter_mut`] 方法。这是一个类迭代器的链,可以对链内的数据并行计算。 12 | 13 | ```rust,edition2018 14 | use rayon::prelude::*; 15 | 16 | fn main() { 17 | let mut arr = [0, 7, 9, 11]; 18 | arr.par_iter_mut().for_each(|p| *p -= 1); 19 | println!("{:?}", arr); 20 | } 21 | ``` 22 | 23 | [`par_iter_mut`]: https://docs.rs/rayon/*/rayon/iter/trait.IntoParallelRefMutIterator.html#tymethod.par_iter_mut 24 | -------------------------------------------------------------------------------- /src/file/dir/png.md: -------------------------------------------------------------------------------- 1 | ## 递归查找所有 png 文件 2 | 3 | 8 | 9 | [![glob-badge]][glob] [![cat-filesystem-badge]][cat-filesystem] 10 | 11 | 递归地查找当前目录中的所有 PNG 文件。在本实例中,`**` 模式用于匹配当前目录及其所有子目录。 12 | 13 | 在路径任意部分使用 `**` 模式,例如,`/media/**/*.png` 匹配 `media` 及其子目录中的所有 PNG 文件。 14 | 15 | ```rust,edition2018,no_run 16 | # use error_chain::error_chain; 17 | 18 | use glob::glob; 19 | # 20 | # error_chain! { 21 | # foreign_links { 22 | # Glob(glob::GlobError); 23 | # Pattern(glob::PatternError); 24 | # } 25 | # } 26 | 27 | fn main() -> Result<()> { 28 | for entry in glob("**/*.png")? { 29 | println!("{}", entry?.display()); 30 | } 31 | 32 | Ok(()) 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /src/algorithms/randomness/rand-passwd.md: -------------------------------------------------------------------------------- 1 | ## 从一组字母数字字符创建随机密码 2 | 3 | 8 | 9 | [![rand-badge]][rand] [![cat-os-badge]][cat-os] 10 | 11 | 随机生成一个给定长度的 ASCII 字符串,范围为 `A-Z,a-z,0-9`,使用[字母数字][`Alphanumeric`]样本。 12 | 13 | ```rust,edition2018 14 | use rand::{thread_rng, Rng}; 15 | use rand::distributions::Alphanumeric; 16 | 17 | fn main() { 18 | let rand_string: String = thread_rng() 19 | .sample_iter(&Alphanumeric) 20 | .take(30) 21 | .map(char::from) 22 | .collect(); 23 | 24 | println!("{}", rand_string); 25 | } 26 | ``` 27 | 28 | [`Alphanumeric`]: https://docs.rs/rand/*/rand/distributions/struct.Alphanumeric.html 29 | -------------------------------------------------------------------------------- /src/algorithms/sorting/sort_float.md: -------------------------------------------------------------------------------- 1 | ## 浮点数 Vector 排序 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-science-badge]][cat-science] 10 | 11 | f32 或 f64 的 vector,可以使用 [`vec::sort_by`] 和 [`PartialOrd::partial_cmp`] 对其进行排序。 12 | 13 | ```rust,edition2018 14 | fn main() { 15 | let mut vec = vec![1.1, 1.15, 5.5, 1.123, 2.0]; 16 | 17 | vec.sort_by(|a, b| a.partial_cmp(b).unwrap()); 18 | 19 | assert_eq!(vec, vec![1.1, 1.123, 1.15, 2.0, 5.5]); 20 | } 21 | ``` 22 | 23 | [`vec::sort_by`]: https://doc.rust-lang.org/std/primitive.slice.html#method.sort_by 24 | [`PartialOrd::partial_cmp`]: https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html#tymethod.partial_cmp 25 | -------------------------------------------------------------------------------- /src/science/mathematics/complex_numbers/create-complex.md: -------------------------------------------------------------------------------- 1 | ## 创建复数 2 | 3 | 8 | 9 | [![num-badge]][num] [![cat-science-badge]][cat-science] 10 | 11 | 创建类型 [`num::complex::Complex`] 的复数,复数的实部和虚部必须是同一类型。 12 | 13 | ```rust,edition2018 14 | fn main() { 15 | let complex_integer = num::complex::Complex::new(10, 20); 16 | let complex_float = num::complex::Complex::new(10.1, 20.1); 17 | 18 | println!("Complex integer: {}", complex_integer); 19 | println!("Complex float: {}", complex_float); 20 | } 21 | ``` 22 | 23 | [`num::complex::Complex`]: https://autumnai.github.io/cuticula/num/complex/struct.Complex.html 24 | -------------------------------------------------------------------------------- /src/science/mathematics/complex_numbers/mathematical-functions.md: -------------------------------------------------------------------------------- 1 | ## 复数的数学函数 2 | 3 | 8 | 9 | [![num-badge]][num] [![cat-science-badge]][cat-science] 10 | 11 | 在与其他数学函数交互时,复数有一系列有趣的特性,尤其是和自然常数 e(欧拉数)类似的正弦相关函数。要将这些函数与复数一起使用,复数类型有几个内置函数,详细请参阅 [`num::complex::Complex`]。 12 | 13 | ```rust,edition2018 14 | use std::f64::consts::PI; 15 | use num::complex::Complex; 16 | 17 | fn main() { 18 | let x = Complex::new(0.0, 2.0*PI); 19 | 20 | println!("e^(2i * pi) = {}", x.exp()); // =~1 21 | } 22 | ``` 23 | 24 | [`num::complex::Complex`]: https://autumnai.github.io/cuticula/num/complex/struct.Complex.html 25 | -------------------------------------------------------------------------------- /src/web/url/fragment.md: -------------------------------------------------------------------------------- 1 | ## 从 URL 移除片段标识符和查询对 2 | 3 | 8 | 9 | [![url-badge]][url] [![cat-net-badge]][cat-net] 10 | 11 | 解析 [`Url`] 结构体,并使用 [`url::Position`] 枚举对其进行切片,以去除不需要的 URL 片段。 12 | 13 | ```rust,edition2018 14 | 15 | 16 | use url::{Url, Position, ParseError}; 17 | 18 | fn main() -> Result<(), ParseError> { 19 | let parsed = Url::parse("https://github.com/rust-lang/rust/issues?labels=E-easy&state=open")?; 20 | let cleaned: &str = &parsed[..Position::AfterPath]; 21 | println!("cleaned: {}", cleaned); 22 | Ok(()) 23 | } 24 | ``` 25 | 26 | [`url::Position`]: https://docs.rs/url/*/url/enum.Position.html 27 | [`Url`]: https://docs.rs/url/*/url/struct.Url.html 28 | -------------------------------------------------------------------------------- /src/development_tools/versioning/semver-prerelease.md: -------------------------------------------------------------------------------- 1 | ## 检查给定版本是否为预发布版本 2 | 3 | 8 | 9 | [![semver-badge]][semver] [![cat-config-badge]][cat-config] 10 | 11 | 给定两个版本,使用 [`is_prerelease`] 断言一个是预发布,另一个不是。 12 | 13 | ```rust,edition2018 14 | use semver::{Version, SemVerError}; 15 | 16 | fn main() -> Result<(), SemVerError> { 17 | let version_1 = Version::parse("1.0.0-alpha")?; 18 | let version_2 = Version::parse("1.0.0")?; 19 | 20 | assert!(version_1.is_prerelease()); 21 | assert!(!version_2.is_prerelease()); 22 | 23 | Ok(()) 24 | } 25 | ``` 26 | 27 | [`is_prerelease`]: https://docs.rs/semver/*/semver/struct.Version.html#method.is_prerelease 28 | -------------------------------------------------------------------------------- /src/os/external/read-env-variable.md: -------------------------------------------------------------------------------- 1 | ## 读取环境变量 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-os-badge]][cat-os] 10 | 11 | 通过 [std::env::var] 读取环境变量。 12 | 13 | ```rust,edition2018,no_run 14 | use std::env; 15 | use std::fs; 16 | use std::io::Error; 17 | 18 | fn main() -> Result<(), Error> { 19 | // 从环境变量 `CONFIG` 读取配置路径 `config_path`。 20 | // 如果 `CONFIG` 未设置,采用默认配置路径。 21 | let config_path = env::var("CONFIG") 22 | .unwrap_or("/etc/myapp/config".to_string()); 23 | 24 | let config: String = fs::read_to_string(config_path)?; 25 | println!("Config: {}", config); 26 | 27 | Ok(()) 28 | } 29 | ``` 30 | 31 | [std::env::var]: https://doc.rust-lang.org/std/env/fn.var.html 32 | -------------------------------------------------------------------------------- /src/compression.md: -------------------------------------------------------------------------------- 1 | # 压缩 2 | 3 | 8 | 9 | ## 使用 tar 包 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [解压 tar 包][ex-tar-decompress] | [![flate2-badge]][flate2] [![tar-badge]][tar] | [![cat-compression-badge]][cat-compression] | 14 | | [压缩目录为 tar 包][ex-tar-compress] | [![flate2-badge]][flate2] [![tar-badge]][tar] | [![cat-compression-badge]][cat-compression] | 15 | | [从路径移除前缀时,解压 tar 包][ex-tar-strip-prefix] | [![flate2-badge]][flate2] [![tar-badge]][tar] | [![cat-compression-badge]][cat-compression] | 16 | 17 | [ex-tar-decompress]: compression/tar.md#解压-tar-包 18 | [ex-tar-compress]: compression/tar.md#压缩目录为-tar-包 19 | [ex-tar-strip-prefix]: compression/tar.md#从路径移除前缀时解压-tar-包 20 | 21 | {{#include links.md}} 22 | -------------------------------------------------------------------------------- /src/development_tools/debugging/log/log-error.md: -------------------------------------------------------------------------------- 1 | ## 记录错误信息到控制台 2 | 3 | 8 | 9 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 10 | 11 | 正确的错误处理会将异常视为错误。下述实例中,通过 `log` 便捷宏 [`log::error!`],将错误记录到 stderr。 12 | 13 | ```rust,edition2018 14 | 15 | fn execute_query(_query: &str) -> Result<(), &'static str> { 16 | Err("I'm afraid I can't do that") 17 | } 18 | 19 | fn main() { 20 | env_logger::init(); 21 | 22 | let response = execute_query("DROP TABLE students"); 23 | if let Err(err) = response { 24 | log::error!("Failed to execute query: {}", err); 25 | } 26 | } 27 | ``` 28 | 29 | [`log::error!`]: https://docs.rs/log/*/log/macro.error.html 30 | -------------------------------------------------------------------------------- /src/science/mathematics/miscellaneous/big-integers.md: -------------------------------------------------------------------------------- 1 | ## 大数 2 | 3 | 8 | 9 | [![num-badge]][num] [![cat-science-badge]][cat-science] 10 | 11 | [`BigInt`] 使得超过 128 位的大整数计算成为可能。 12 | 13 | ```rust,edition2018 14 | use num::bigint::{BigInt, ToBigInt}; 15 | 16 | fn factorial(x: i32) -> BigInt { 17 | if let Some(mut factorial) = 1.to_bigint() { 18 | for i in 1..(x+1) { 19 | factorial = factorial * i; 20 | } 21 | factorial 22 | } 23 | else { 24 | panic!("Failed to calculate factorial!"); 25 | } 26 | } 27 | 28 | fn main() { 29 | println!("{}! equals {}", 100, factorial(100)); 30 | } 31 | ``` 32 | 33 | [`BigInt`]: https://docs.rs/num/0.2.0/num/struct.BigInt.html -------------------------------------------------------------------------------- /src/development_tools/debugging/log/log-stdout.md: -------------------------------------------------------------------------------- 1 | ## 记录信息时,用标准输出 stdout 替换标准错误 stderr 2 | 3 | 8 | 9 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 10 | 11 | 使用 [`Builder::target`] 创建自定义的日志记录器配置,将日志输出的目标设置为 [`Target::Stdout`]。 12 | 13 | ```rust,edition2018 14 | 15 | use env_logger::{Builder, Target}; 16 | 17 | fn main() { 18 | Builder::new() 19 | .target(Target::Stdout) 20 | .init(); 21 | 22 | log::error!("This error has been printed to Stdout"); 23 | } 24 | ``` 25 | 26 | [`Builder::target`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html#method.target 27 | [`Target::Stdout`]: https://docs.rs/env_logger/*/env_logger/fmt/enum.Target.html 28 | -------------------------------------------------------------------------------- /src/errors.md: -------------------------------------------------------------------------------- 1 | # 错误处理 2 | 3 | 8 | 9 | ## 处理错误变量 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [在 main 方法中对错误适当处理][ex-error-chain-simple-error-handling] | [![error-chain-badge]][error-chain] | [![cat-rust-patterns-badge]][cat-rust-patterns] | 14 | | [避免在错误转变过程中遗漏错误][ex-error-chain-avoid-discarding] | [![error-chain-badge]][error-chain] | [![cat-rust-patterns-badge]][cat-rust-patterns] | 15 | | [获取复杂错误场景的回溯][ex-error-chain-backtrace] | [![error-chain-badge]][error-chain] | [![cat-rust-patterns-badge]][cat-rust-patterns] | 16 | 17 | [ex-error-chain-simple-error-handling]: errors/handle.md#在-main-方法中对错误适当处理 18 | [ex-error-chain-avoid-discarding]: errors/handle.md#避免在错误转变过程中遗漏错误 19 | [ex-error-chain-backtrace]: errors/handle.md#获取复杂错误场景的回溯 20 | 21 | {{#include links.md}} 22 | -------------------------------------------------------------------------------- /src/science/mathematics/linear_algebra/multiply-matrices.md: -------------------------------------------------------------------------------- 1 | ## 矩阵相乘 2 | 3 | 8 | 9 | [![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science] 10 | 11 | 使用 [`ndarray::arr2`] 创建两个矩阵,并使用 [`ndarray::ArrayBase::dot`] 对它们执行矩阵乘法。 12 | 13 | ```rust,edition2018 14 | use ndarray::arr2; 15 | 16 | fn main() { 17 | let a = arr2(&[[1, 2, 3], 18 | [4, 5, 6]]); 19 | 20 | let b = arr2(&[[6, 3], 21 | [5, 2], 22 | [4, 1]]); 23 | 24 | println!("{}", a.dot(&b)); 25 | } 26 | ``` 27 | 28 | [`ndarray::arr2`]: https://docs.rs/ndarray/*/ndarray/fn.arr2.html 29 | [`ndarray::ArrayBase::dot`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.dot-1 30 | -------------------------------------------------------------------------------- /src/web/url/parse.md: -------------------------------------------------------------------------------- 1 | ## 解析 URL 字符串为 `Url` 类型 2 | 3 | 8 | 9 | [![url-badge]][url] [![cat-net-badge]][cat-net] 10 | 11 | `url` crate 中的 [`parse`] 方法验证并解析 `&str` 切片为 [`Url`] 结构体。如果输入字符串的格式不正确,解析方法 [`parse`] 会返回 `Result`。 12 | 13 | 一旦 URL 被解析,它就可以使用 `Url` 结构体类型中的所有方法。 14 | 15 | ```rust,edition2018 16 | 17 | use url::{Url, ParseError}; 18 | 19 | fn main() -> Result<(), ParseError> { 20 | let s = "https://github.com/rust-lang/rust/issues?labels=E-easy&state=open"; 21 | 22 | let parsed = Url::parse(s)?; 23 | println!("The path part of the URL is: {}", parsed.path()); 24 | 25 | Ok(()) 26 | } 27 | ``` 28 | 29 | [`parse`]: https://docs.rs/url/*/url/struct.Url.html#method.parse 30 | [`Url`]: https://docs.rs/url/*/url/struct.Url.html 31 | -------------------------------------------------------------------------------- /src/science/mathematics/linear_algebra/invert-matrix.md: -------------------------------------------------------------------------------- 1 | ## 矩阵求逆 2 | 3 | 8 | 9 | [![nalgebra-badge]][nalgebra] [![cat-science-badge]][cat-science] 10 | 11 | 用 [`nalgebra::Matrix3`] 创建一个 3x3 的矩阵,如果可能的话,将其求逆。 12 | 13 | ```rust,edition2018 14 | use nalgebra::Matrix3; 15 | 16 | fn main() { 17 | let m1 = Matrix3::new(2.0, 1.0, 1.0, 3.0, 2.0, 1.0, 2.0, 1.0, 2.0); 18 | println!("m1 = {}", m1); 19 | match m1.try_inverse() { 20 | Some(inv) => { 21 | println!("The inverse of m1 is: {}", inv); 22 | } 23 | None => { 24 | println!("m1 is not invertible!"); 25 | } 26 | } 27 | } 28 | ``` 29 | 30 | [`nalgebra::Matrix3`]: https://docs.rs/nalgebra/*/nalgebra/base/type.Matrix3.html 31 | -------------------------------------------------------------------------------- /src/file/dir/duplicate-name.md: -------------------------------------------------------------------------------- 1 | ## 递归查找重名文件 2 | 3 | 8 | 9 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 10 | 11 | 在当前目录中递归查找重复的文件名,只打印一次。 12 | 13 | ```rust,edition2018,no_run 14 | use std::collections::HashMap; 15 | use walkdir::WalkDir; 16 | 17 | fn main() { 18 | let mut filenames = HashMap::new(); 19 | 20 | for entry in WalkDir::new(".") 21 | .into_iter() 22 | .filter_map(Result::ok) 23 | .filter(|e| !e.file_type().is_dir()) { 24 | let f_name = String::from(entry.file_name().to_string_lossy()); 25 | let counter = filenames.entry(f_name.clone()).or_insert(0); 26 | *counter += 1; 27 | 28 | if *counter == 2 { 29 | println!("{}", f_name); 30 | } 31 | } 32 | } 33 | ``` 34 | -------------------------------------------------------------------------------- /theme/css/print.css: -------------------------------------------------------------------------------- 1 | 2 | #sidebar, 3 | #menu-bar, 4 | .nav-chapters, 5 | .mobile-nav-chapters { 6 | display: none; 7 | } 8 | 9 | #page-wrapper.page-wrapper { 10 | transform: none; 11 | margin-left: 0px; 12 | overflow-y: initial; 13 | } 14 | 15 | #content { 16 | max-width: none; 17 | margin: 0; 18 | padding: 0; 19 | } 20 | 21 | .page { 22 | overflow-y: initial; 23 | } 24 | 25 | code { 26 | background-color: #666666; 27 | border-radius: 5px; 28 | 29 | /* Force background to be printed in Chrome */ 30 | -webkit-print-color-adjust: exact; 31 | } 32 | 33 | pre > .buttons { 34 | z-index: 2; 35 | } 36 | 37 | a, a:visited, a:active, a:hover { 38 | color: #4183c4; 39 | text-decoration: none; 40 | } 41 | 42 | h1, h2, h3, h4, h5, h6 { 43 | page-break-inside: avoid; 44 | page-break-after: avoid; 45 | } 46 | 47 | pre, code { 48 | page-break-inside: avoid; 49 | white-space: pre-wrap; 50 | } 51 | 52 | .fa { 53 | display: none !important; 54 | } 55 | -------------------------------------------------------------------------------- /src/algorithms/randomness/rand.md: -------------------------------------------------------------------------------- 1 | ## 生成随机数 2 | 3 | 8 | 9 | [![rand-badge]][rand] [![cat-science-badge]][cat-science] 10 | 11 | 在随机数生成器 [`rand::Rng`] 的帮助下,通过 [`rand::thread_rng`] 生成随机数。可以开启多个线程,每个线程都有一个初始化的生成器。整数在其类型范围内均匀分布,浮点数是从 0 均匀分布到 1,但不包括 1。 12 | 13 | ```rust,edition2018 14 | use rand::Rng; 15 | 16 | fn main() { 17 | let mut rng = rand::thread_rng(); 18 | 19 | let n1: u8 = rng.gen(); 20 | let n2: u16 = rng.gen(); 21 | println!("Random u8: {}", n1); 22 | println!("Random u16: {}", n2); 23 | println!("Random u32: {}", rng.gen::()); 24 | println!("Random i32: {}", rng.gen::()); 25 | println!("Random float: {}", rng.gen::()); 26 | } 27 | ``` 28 | 29 | [`rand::Rng`]: https://docs.rs/rand/*/rand/trait.Rng.html 30 | [`rand::thread_rng`]: https://docs.rs/rand/*/rand/fn.thread_rng.html 31 | -------------------------------------------------------------------------------- /src/science/mathematics/linear_algebra/add-matrices.md: -------------------------------------------------------------------------------- 1 | ## 矩阵相加 2 | 3 | 8 | 9 | [![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science] 10 | 11 | 使用 [`ndarray::arr2`] 创建两个二维(2-D)矩阵,并按元素方式求和。 12 | 13 | 注意:sum 的计算方式为 `let sum = &a + &b`,借用 `&` 运算符获得 `a` 和 `b` 的引用,可避免销毁他们,使它们可以稍后显示。这样,就创建了一个包含其和的新数组。 14 | 15 | ```rust,edition2018 16 | use ndarray::arr2; 17 | 18 | fn main() { 19 | let a = arr2(&[[1, 2, 3], 20 | [4, 5, 6]]); 21 | 22 | let b = arr2(&[[6, 5, 4], 23 | [3, 2, 1]]); 24 | 25 | let sum = &a + &b; 26 | 27 | println!("{}", a); 28 | println!("+"); 29 | println!("{}", b); 30 | println!("="); 31 | println!("{}", sum); 32 | } 33 | ``` 34 | 35 | [`ndarray::arr2`]: https://docs.rs/ndarray/*/ndarray/fn.arr2.html 36 | -------------------------------------------------------------------------------- /src/compression/tar/tar-decompress.md: -------------------------------------------------------------------------------- 1 | ## 解压 tar 包 2 | 3 | 8 | 9 | [![flate2-badge]][flate2] [![tar-badge]][tar] [![cat-compression-badge]][cat-compression] 10 | 11 | 从当前工作目录中的压缩包 `archive.tar.gz`,解压([`GzDecoder`])和提取([`Archive::unpack`])所有文件,并放在同一位置。 12 | 13 | ```rust,edition2018,no_run 14 | 15 | use std::fs::File; 16 | use flate2::read::GzDecoder; 17 | use tar::Archive; 18 | 19 | fn main() -> Result<(), std::io::Error> { 20 | let path = "archive.tar.gz"; 21 | 22 | let tar_gz = File::open(path)?; 23 | let tar = GzDecoder::new(tar_gz); 24 | let mut archive = Archive::new(tar); 25 | archive.unpack(".")?; 26 | 27 | Ok(()) 28 | } 29 | ``` 30 | 31 | [`Archive::unpack`]: https://docs.rs/tar/*/tar/struct.Archive.html#method.unpack 32 | [`GzDecoder`]: https://docs.rs/flate2/*/flate2/read/struct.GzDecoder.html 33 | -------------------------------------------------------------------------------- /src/text/string_parsing/graphemes.md: -------------------------------------------------------------------------------- 1 | ## 收集 Unicode 字符 2 | 3 | 8 | 9 | [![unicode-segmentation-badge]][`unicode-segmentation`] [![cat-text-processing-badge]][cat-text-processing] 10 | 11 | 使用 [`unicode-segmentation`] crate 中的 [`UnicodeSegmentation::graphemes`] 函数,从 UTF-8 字符串中收集个别的 Unicode 字符。 12 | 13 | ```rust,edition2018 14 | use unicode_segmentation::UnicodeSegmentation; 15 | 16 | fn main() { 17 | let name = "José Guimarães\r\n"; 18 | let graphemes = UnicodeSegmentation::graphemes(name, true) 19 | .collect::>(); 20 | assert_eq!(graphemes[3], "é"); 21 | } 22 | ``` 23 | 24 | [`UnicodeSegmentation::graphemes`]: https://docs.rs/unicode-segmentation/*/unicode_segmentation/trait.UnicodeSegmentation.html#tymethod.graphemes 25 | [`unicode-segmentation`]: https://docs.rs/unicode-segmentation/1.2.1/unicode_segmentation/ 26 | -------------------------------------------------------------------------------- /src/cryptography.md: -------------------------------------------------------------------------------- 1 | # 密码学 2 | 3 | 8 | 9 | ## 散列(哈希) 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [计算文件的 SHA-256 摘要][ex-sha-digest] | [![ring-badge]][ring] [![data-encoding-badge]][data-encoding] | [![cat-cryptography-badge]][cat-cryptography] | 14 | | [使用 HMAC 摘要对消息进行签名和验证][ex-hmac] | [![ring-badge]][ring] | [![cat-cryptography-badge]][cat-cryptography] | 15 | 16 | ## 加密 17 | 18 | | 实例名称 | Crates | 类别 | 19 | |--------|--------|------------| 20 | | [使用 PBKDF2 对密码进行加密(salt)和散列(hash)运算][ex-pbkdf2] | [![ring-badge]][ring] [![data-encoding-badge]][data-encoding] | [![cat-cryptography-badge]][cat-cryptography] | 21 | 22 | [ex-sha-digest]: cryptography/hashing.md#计算文件的-sha-256-摘要 23 | [ex-hmac]: cryptography/hashing.md#使用-hmac-摘要对消息进行签名和验证 24 | 25 | [ex-pbkdf2]: cryptography/encryption.md#使用-pbkdf2-对密码进行加密salt和散列hash运算 26 | 27 | {{#include links.md}} 28 | -------------------------------------------------------------------------------- /src/web/url/new.md: -------------------------------------------------------------------------------- 1 | ## 从基本 URL 创建新 URLs 2 | 3 | 8 | 9 | [![url-badge]][url] [![cat-net-badge]][cat-net] 10 | 11 | [`join`] 方法从基路径和相对路径创建新的 URL。 12 | 13 | ```rust,edition2018 14 | 15 | use url::{Url, ParseError}; 16 | 17 | fn main() -> Result<(), ParseError> { 18 | let path = "/rust-lang/cargo"; 19 | 20 | let gh = build_github_url(path)?; 21 | 22 | assert_eq!(gh.as_str(), "https://github.com/rust-lang/cargo"); 23 | println!("The joined URL is: {}", gh); 24 | 25 | Ok(()) 26 | } 27 | 28 | fn build_github_url(path: &str) -> Result { 29 | const GITHUB: &'static str = "https://github.com"; 30 | 31 | let base = Url::parse(GITHUB).expect("hardcoded URL is known to be valid"); 32 | let joined = base.join(path)?; 33 | 34 | Ok(joined) 35 | } 36 | ``` 37 | 38 | [`join`]: https://docs.rs/url/*/url/struct.Url.html#method.join 39 | -------------------------------------------------------------------------------- /src/algorithms/randomness/rand-choose.md: -------------------------------------------------------------------------------- 1 | ## 从一组用户定义字符创建随机密码 2 | 3 | 8 | 9 | [![rand-badge]][rand] [![cat-os-badge]][cat-os] 10 | 11 | 使用用户自定义的字节字符串,使用 [`gen_range`] 函数,随机生成一个给定长度的 ASCII 字符串。 12 | 13 | ```rust,edition2018 14 | fn main() { 15 | use rand::Rng; 16 | const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ 17 | abcdefghijklmnopqrstuvwxyz\ 18 | 0123456789)(*&^%$#@!~"; 19 | const PASSWORD_LEN: usize = 30; 20 | let mut rng = rand::thread_rng(); 21 | 22 | let password: String = (0..PASSWORD_LEN) 23 | .map(|_| { 24 | let idx = rng.gen_range(0..CHARSET.len()); 25 | CHARSET[idx] as char 26 | }) 27 | .collect(); 28 | 29 | println!("{:?}", password); 30 | } 31 | ``` 32 | 33 | [`gen_range`]: https://docs.rs/rand/*/rand/trait.Rng.html#method.gen_range 34 | -------------------------------------------------------------------------------- /src/file/dir/sizes.md: -------------------------------------------------------------------------------- 1 | ## 在给定深度的目录,递归计算文件大小 2 | 3 | 8 | 9 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 10 | 11 | 通过 [`WalkDir::min_depth`] 和 [`WalkDir::max_depth`] 方法,可以灵活设置目录的递归深度。下面的实例计算了 3 层子文件夹深度的所有文件的大小总和,计算中忽略根文件夹中的文件。 12 | 13 | ```rust,edition2018 14 | use walkdir::WalkDir; 15 | 16 | fn main() { 17 | let total_size = WalkDir::new(".") 18 | .min_depth(1) 19 | .max_depth(3) 20 | .into_iter() 21 | .filter_map(|entry| entry.ok()) 22 | .filter_map(|entry| entry.metadata().ok()) 23 | .filter(|metadata| metadata.is_file()) 24 | .fold(0, |acc, m| acc + m.len()); 25 | 26 | println!("Total size: {} bytes.", total_size); 27 | } 28 | ``` 29 | 30 | [`WalkDir::max_depth`]: https://docs.rs/walkdir/*/walkdir/struct.WalkDir.html#method.max_depth 31 | [`WalkDir::min_depth`]: https://docs.rs/walkdir/*/walkdir/struct.WalkDir.html#method.min_depth 32 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 zzy (linshi@budshome.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/encoding/csv/delimiter.md: -------------------------------------------------------------------------------- 1 | ## 读取有不同分隔符的 CSV 记录 2 | 3 | 8 | 9 | [![csv-badge]][csv] [![cat-encoding-badge]][cat-encoding] 10 | 11 | 使用制表(tab)分隔符 [`delimiter`] 读取 CSV 记录。 12 | 13 | ```rust,edition2018 14 | use csv::Error; 15 | use serde::Deserialize; 16 | #[derive(Debug, Deserialize)] 17 | struct Record { 18 | name: String, 19 | place: String, 20 | #[serde(deserialize_with = "csv::invalid_option")] 21 | id: Option, 22 | } 23 | 24 | use csv::ReaderBuilder; 25 | 26 | fn main() -> Result<(), Error> { 27 | let data = "name\tplace\tid 28 | Mark\tMelbourne\t46 29 | Ashley\tZurich\t92"; 30 | 31 | let mut reader = ReaderBuilder::new().delimiter(b'\t').from_reader(data.as_bytes()); 32 | for result in reader.deserialize::() { 33 | println!("{:?}", result?); 34 | } 35 | 36 | Ok(()) 37 | } 38 | ``` 39 | 40 | [`delimiter`]: https://docs.rs/csv/1.0.0-beta.3/csv/struct.ReaderBuilder.html#method.delimiter 41 | -------------------------------------------------------------------------------- /src/net/server/listen-unused.md: -------------------------------------------------------------------------------- 1 | ## 监听未使用的 TCP/IP 端口 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-net-badge]][cat-net] 10 | 11 | 在本实例中,程序将监听显示在控制台上的端口,直到一个请求被发出。当将端口设置为 0 时,`SocketAddrV4` 会分配一个随机端口。 12 | 13 | ```rust,edition2018,no_run 14 | use std::net::{SocketAddrV4, Ipv4Addr, TcpListener}; 15 | use std::io::{Read, Error}; 16 | 17 | fn main() -> Result<(), Error> { 18 | let loopback = Ipv4Addr::new(127, 0, 0, 1); 19 | let socket = SocketAddrV4::new(loopback, 0); 20 | let listener = TcpListener::bind(socket)?; 21 | let port = listener.local_addr()?; 22 | println!("Listening on {}, access this port to end the program", port); 23 | let (mut tcp_stream, addr) = listener.accept()?; // 阻塞,直到被请求 24 | println!("Connection received! {:?} is sending data.", addr); 25 | let mut input = String::new(); 26 | let _ = tcp_stream.read_to_string(&mut input)?; 27 | println!("{:?} says {}", addr, input); 28 | Ok(()) 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /src/cryptography/hashing/hmac.md: -------------------------------------------------------------------------------- 1 | ## 使用 HMAC 摘要对消息进行签名和验证 2 | 3 | 8 | 9 | [![ring-badge]][ring] [![cat-cryptography-badge]][cat-cryptography] 10 | 11 | 使用 [`ring::hmac`] 创建字符串的签名 [`hmac::Signature`],然后验证签名是否正确。 12 | 13 | ```rust,edition2018 14 | use ring::{hmac, rand}; 15 | use ring::rand::SecureRandom; 16 | use ring::error::Unspecified; 17 | 18 | fn main() -> Result<(), Unspecified> { 19 | let mut key_value = [0u8; 48]; 20 | let rng = rand::SystemRandom::new(); 21 | rng.fill(&mut key_value)?; 22 | let key = hmac::Key::new(hmac::HMAC_SHA256, &key_value); 23 | 24 | let message = "Legitimate and important message."; 25 | let signature = hmac::sign(&key, message.as_bytes()); 26 | hmac::verify(&key, message.as_bytes(), signature.as_ref())?; 27 | 28 | Ok(()) 29 | } 30 | ``` 31 | 32 | [`hmac::Signature`]: https://briansmith.org/rustdoc/ring/hmac/struct.Signature.html 33 | [`ring::hmac`]: https://briansmith.org/rustdoc/ring/hmac/ 34 | -------------------------------------------------------------------------------- /src/development_tools/debugging/log/log-debug.md: -------------------------------------------------------------------------------- 1 | ## 记录调试信息到控制台 2 | 3 | 8 | 9 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 10 | 11 | `log` crate 提供了日志工具,`env_logger` crate 通过环境变量配置日志记录。[`log::debug!`] 宏的工作方式类似于其它 [`std::fmt`] 格式化的字符串。 12 | 13 | ```rust,edition2018 14 | 15 | fn execute_query(query: &str) { 16 | log::debug!("Executing query: {}", query); 17 | } 18 | 19 | fn main() { 20 | env_logger::init(); 21 | 22 | execute_query("DROP TABLE students"); 23 | } 24 | ``` 25 | 26 | 运行上述代码时,并没有输出信息被打印。因为默认情况下,日志级别为 `error`,任何较低级别的日志信息都将被忽略。 27 | 28 | 设置 `RUST_LOG` 环境变量以打印消息: 29 | 30 | ``` 31 | $ RUST_LOG=debug cargo run 32 | ``` 33 | 34 | Cargo 运行后,会在输出的最后一行打印出调试信息: 35 | 36 | ``` 37 | DEBUG:main: Executing query: DROP TABLE students 38 | ``` 39 | 40 | [`log::debug!`]: https://docs.rs/log/*/log/macro.debug.html 41 | [`std::fmt`]: https://doc.rust-lang.org/std/fmt/ 42 | -------------------------------------------------------------------------------- /src/encoding/string/base64.md: -------------------------------------------------------------------------------- 1 | ## 编码和解码 base64 2 | 3 | 8 | 9 | [![base64-badge]][base64] [![cat-encoding-badge]][cat-encoding] 10 | 11 | 使用 [`encode`] 将字节切片编码为 `base64` 字符串,对 `base64` 字符串解码使用 [`decode`]。 12 | 13 | ```rust,edition2018 14 | # use error_chain::error_chain; 15 | 16 | use std::str; 17 | use base64::{encode, decode}; 18 | # 19 | # error_chain! { 20 | # foreign_links { 21 | # Base64(base64::DecodeError); 22 | # Utf8Error(str::Utf8Error); 23 | # } 24 | # } 25 | 26 | fn main() -> Result<()> { 27 | let hello = b"hello rustaceans"; 28 | let encoded = encode(hello); 29 | let decoded = decode(&encoded)?; 30 | 31 | println!("origin: {}", str::from_utf8(hello)?); 32 | println!("base64 encoded: {}", encoded); 33 | println!("back to origin: {}", str::from_utf8(&decoded)?); 34 | 35 | Ok(()) 36 | } 37 | ``` 38 | 39 | [`decode`]: https://docs.rs/base64/*/base64/fn.decode.html 40 | [`encode`]: https://docs.rs/base64/*/base64/fn.encode.html 41 | -------------------------------------------------------------------------------- /src/encoding/csv/invalid.md: -------------------------------------------------------------------------------- 1 | ## 用 Serde 处理无效的 CSV 数据 2 | 3 | 8 | 9 | [![csv-badge]][csv] [![serde-badge]][serde] [![cat-encoding-badge]][cat-encoding] 10 | 11 | CSV 文件通常包含无效数据。对于这些情形,`csv` crate 提供了一个自定义的反序列化程序 [`csv::invalid_option`],它自动将无效数据转换为 None 值。 12 | 13 | ```rust,edition2018 14 | use csv::Error; 15 | use serde::Deserialize; 16 | 17 | #[derive(Debug, Deserialize)] 18 | struct Record { 19 | name: String, 20 | place: String, 21 | #[serde(deserialize_with = "csv::invalid_option")] 22 | id: Option, 23 | } 24 | 25 | fn main() -> Result<(), Error> { 26 | let data = "name,place,id 27 | mark,sydney,46.5 28 | ashley,zurich,92 29 | akshat,delhi,37 30 | alisha,colombo,xyz"; 31 | 32 | let mut rdr = csv::Reader::from_reader(data.as_bytes()); 33 | for result in rdr.deserialize() { 34 | let record: Record = result?; 35 | println!("{:?}", record); 36 | } 37 | 38 | Ok(()) 39 | } 40 | ``` 41 | 42 | [`csv::invalid_option`]: https://docs.rs/csv/*/csv/fn.invalid_option.html 43 | -------------------------------------------------------------------------------- /src/mem/global_static/lazy-constant.md: -------------------------------------------------------------------------------- 1 | ## 声明延迟计算常量 2 | 3 | 8 | 9 | [![lazy_static-badge]][lazy_static] [![cat-caching-badge]][cat-caching] [![cat-rust-patterns-badge]][cat-rust-patterns] 10 | 11 | 声明延迟计算的常量 [`HashMap`]。[`HashMap`] 将被计算一次,随后存储在全局静态(全局堆栈)引用。 12 | 13 | ```rust,edition2018 14 | use lazy_static::lazy_static; 15 | use std::collections::HashMap; 16 | 17 | lazy_static! { 18 | static ref PRIVILEGES: HashMap<&'static str, Vec<&'static str>> = { 19 | let mut map = HashMap::new(); 20 | map.insert("James", vec!["user", "admin"]); 21 | map.insert("Jim", vec!["user"]); 22 | map 23 | }; 24 | } 25 | 26 | fn show_access(name: &str) { 27 | let access = PRIVILEGES.get(name); 28 | println!("{}: {:?}", name, access); 29 | } 30 | 31 | fn main() { 32 | let access = PRIVILEGES.get("James"); 33 | println!("James: {:?}", access); 34 | 35 | show_access("Jim"); 36 | } 37 | ``` 38 | 39 | [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html 40 | -------------------------------------------------------------------------------- /src/encoding/string/hex.md: -------------------------------------------------------------------------------- 1 | ## 编码和解码十六进制 2 | 3 | 8 | 9 | [![data-encoding-badge]][data-encoding] [![cat-encoding-badge]][cat-encoding] 10 | 11 | [`data_encoding`] crate 提供了 `HEXUPPER::encode` 方法,该方法接受 `&[u8]` 参数并返回十六进制数据的字符串 `String`。 12 | 13 | 类似地,[`data_encoding`] crate 提供了 `HEXUPPER::decode` 方法,该方法接受 `&[u8]` 参数。如果输入数据被成功解码,则返回 `Vec`。 14 | 15 | 下面的实例将 `&[u8]` 数据转换为等效的十六进制数据,然后将此值与预期值进行比较。 16 | 17 | ```rust,edition2018 18 | use data_encoding::{HEXUPPER, DecodeError}; 19 | 20 | fn main() -> Result<(), DecodeError> { 21 | let original = b"The quick brown fox jumps over the lazy dog."; 22 | let expected = "54686520717569636B2062726F776E20666F78206A756D7073206F76\ 23 | 657220746865206C617A7920646F672E"; 24 | 25 | let encoded = HEXUPPER.encode(original); 26 | assert_eq!(encoded, expected); 27 | 28 | let decoded = HEXUPPER.decode(&encoded.into_bytes())?; 29 | assert_eq!(&decoded[..], &original[..]); 30 | 31 | Ok(()) 32 | } 33 | ``` 34 | 35 | [`data_encoding`]: https://docs.rs/data-encoding/*/data_encoding/ 36 | -------------------------------------------------------------------------------- /src/os/external/error-file.md: -------------------------------------------------------------------------------- 1 | ## 将子进程的 stdout 和 stderr 重定向到同一个文件 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-os-badge]][cat-os] 10 | 11 | 生成子进程并将 `stdout` 和 `stderr` 重定向到同一个文件。它遵循与[运行管道传输的外部命令](#运行管道传输的外部命令)相同的思想,但是 [`process::Stdio`] 会将输出写入指定的文件。对 `stdout` 和 `stderr` 而言,[`File::try_clone`] 引用相同的文件句柄。它将确保两个句柄使用相同的光标位置进行写入。 12 | 13 | 下面的实例等同于运行 Unix shell 命令 `ls 14 | . oops >out.txt 2>&1`。 15 | 16 | ```rust,edition2018,no_run 17 | use std::fs::File; 18 | use std::io::Error; 19 | use std::process::{Command, Stdio}; 20 | 21 | fn main() -> Result<(), Error> { 22 | let outputs = File::create("out.txt")?; 23 | let errors = outputs.try_clone()?; 24 | 25 | Command::new("ls") 26 | .args(&[".", "oops"]) 27 | .stdout(Stdio::from(outputs)) 28 | .stderr(Stdio::from(errors)) 29 | .spawn()? 30 | .wait_with_output()?; 31 | 32 | Ok(()) 33 | } 34 | ``` 35 | 36 | [`File::try_clone`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.try_clone 37 | [`process::Stdio`]: https://doc.rust-lang.org/std/process/struct.Stdio.html 38 | -------------------------------------------------------------------------------- /src/encoding/csv/serde-serialize.md: -------------------------------------------------------------------------------- 1 | ## 用 Serde 将记录序列化为 CSV 2 | 3 | 8 | 9 | [![csv-badge]][csv] [![serde-badge]][serde] [![cat-encoding-badge]][cat-encoding] 10 | 11 | 下面的实例展示如何使用 [serde] crate 将自定义结构体序列化为 CSV 记录。 12 | 13 | ```rust,edition2018 14 | # use error_chain::error_chain; 15 | use serde::Serialize; 16 | use std::io; 17 | # 18 | # error_chain! { 19 | # foreign_links { 20 | # IOError(std::io::Error); 21 | # CSVError(csv::Error); 22 | # } 23 | # } 24 | 25 | #[derive(Serialize)] 26 | struct Record<'a> { 27 | name: &'a str, 28 | place: &'a str, 29 | id: u64, 30 | } 31 | 32 | fn main() -> Result<()> { 33 | let mut wtr = csv::Writer::from_writer(io::stdout()); 34 | 35 | let rec1 = Record { name: "Mark", place: "Melbourne", id: 56}; 36 | let rec2 = Record { name: "Ashley", place: "Sydney", id: 64}; 37 | let rec3 = Record { name: "Akshat", place: "Delhi", id: 98}; 38 | 39 | wtr.serialize(rec1)?; 40 | wtr.serialize(rec2)?; 41 | wtr.serialize(rec3)?; 42 | 43 | wtr.flush()?; 44 | 45 | Ok(()) 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /src/datetime/duration/profile.md: -------------------------------------------------------------------------------- 1 | ## 测量运行时间 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-time-badge]][cat-time] 10 | 11 | 测量从 [`time::Instant::now`] 开始运行的时间 [`time::Instant::elapsed`]。 12 | 13 | 调用 [`time::Instant::elapsed`] 将返回 [`time::Duration`],我们将在实例末尾打印该时间。此方法不会更改或者重置 [`time::Instant`] 对象。 14 | 15 | ```rust,edition2018 16 | use std::time::{Duration, Instant}; 17 | # use std::thread; 18 | # 19 | # fn expensive_function() { 20 | # thread::sleep(Duration::from_secs(1)); 21 | # } 22 | 23 | fn main() { 24 | let start = Instant::now(); 25 | expensive_function(); 26 | let duration = start.elapsed(); 27 | 28 | println!("Time elapsed in expensive_function() is: {:?}", duration); 29 | } 30 | ``` 31 | 32 | [`time::Duration`]: https://doc.rust-lang.org/std/time/struct.Duration.html 33 | [`time::Instant::elapsed`]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.elapsed 34 | [`time::Instant::now`]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.now 35 | [`time::Instant`]:https://doc.rust-lang.org/std/time/struct.Instant.html 36 | -------------------------------------------------------------------------------- /src/file/dir/find-file.md: -------------------------------------------------------------------------------- 1 | ## 使用给定断言递归查找所有文件 2 | 3 | 8 | 9 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 10 | 11 | 在当前目录中查找最近一天内修改的 JSON 文件。使用 [`follow_links`] 确保软链接(符号链接)像普通目录和文件一样被按照当前查找规则执行。 12 | 13 | ```rust,edition2018,no_run 14 | # use error_chain::error_chain; 15 | 16 | use walkdir::WalkDir; 17 | # 18 | # error_chain! { 19 | # foreign_links { 20 | # WalkDir(walkdir::Error); 21 | # Io(std::io::Error); 22 | # SystemTime(std::time::SystemTimeError); 23 | # } 24 | # } 25 | 26 | fn main() -> Result<()> { 27 | for entry in WalkDir::new(".") 28 | .follow_links(true) 29 | .into_iter() 30 | .filter_map(|e| e.ok()) { 31 | let f_name = entry.file_name().to_string_lossy(); 32 | let sec = entry.metadata()?.modified()?; 33 | 34 | if f_name.ends_with(".json") && sec.elapsed()?.as_secs() < 86400 { 35 | println!("{}", f_name); 36 | } 37 | } 38 | 39 | Ok(()) 40 | } 41 | ``` 42 | 43 | [`follow_links`]: https://docs.rs/walkdir/*/walkdir/struct.WalkDir.html#method.follow_links 44 | -------------------------------------------------------------------------------- /src/text/regex/email.md: -------------------------------------------------------------------------------- 1 | ## 验证并提取电子邮件登录信息 2 | 3 | 8 | 9 | [![regex-badge]][regex] [![lazy_static-badge]][lazy_static] [![cat-text-processing-badge]][cat-text-processing] 10 | 11 | 验证电子邮件地址的格式是否正确,并提取 @ 符号之前的所有内容。 12 | 13 | ```rust,edition2018 14 | use lazy_static::lazy_static; 15 | 16 | use regex::Regex; 17 | 18 | fn extract_login(input: &str) -> Option<&str> { 19 | lazy_static! { 20 | static ref RE: Regex = Regex::new(r"(?x) 21 | ^(?P[^@\s]+)@ 22 | ([[:word:]]+\.)* 23 | [[:word:]]+$ 24 | ").unwrap(); 25 | } 26 | RE.captures(input).and_then(|cap| { 27 | cap.name("login").map(|login| login.as_str()) 28 | }) 29 | } 30 | 31 | fn main() { 32 | assert_eq!(extract_login(r"I❤email@example.com"), Some(r"I❤email")); 33 | assert_eq!( 34 | extract_login(r"sdf+sdsfsd.as.sdsd@jhkk.d.rl"), 35 | Some(r"sdf+sdsfsd.as.sdsd") 36 | ); 37 | assert_eq!(extract_login(r"More@Than@One@at.com"), None); 38 | assert_eq!(extract_login(r"Not an email@email"), None); 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /src/web/mime/string.md: -------------------------------------------------------------------------------- 1 | ## 从字符串获取 MIME 类型 2 | 3 | 8 | 9 | [![mime-badge]][mime] [![cat-encoding-badge]][cat-encoding] 10 | 11 | 下面的实例展示如何使用 [mime] crate 从字符串解析出 [`MIME`] 类型。[`FromStrError`] 结构体在 `unwrap_or` 子句中生成默认的 [`MIME`] 类型。 12 | 13 | ```rust,edition2018 14 | use mime::{Mime, APPLICATION_OCTET_STREAM}; 15 | 16 | fn main() { 17 | let invalid_mime_type = "i n v a l i d"; 18 | let default_mime = invalid_mime_type 19 | .parse::() 20 | .unwrap_or(APPLICATION_OCTET_STREAM); 21 | 22 | println!( 23 | "MIME for {:?} used default value {:?}", 24 | invalid_mime_type, default_mime 25 | ); 26 | 27 | let valid_mime_type = "TEXT/PLAIN"; 28 | let parsed_mime = valid_mime_type 29 | .parse::() 30 | .unwrap_or(APPLICATION_OCTET_STREAM); 31 | 32 | println!( 33 | "MIME for {:?} was parsed as {:?}", 34 | valid_mime_type, parsed_mime 35 | ); 36 | } 37 | ``` 38 | 39 | [`FromStrError`]: https://docs.rs/mime/*/mime/struct.FromStrError.html 40 | [`MIME`]: https://docs.rs/mime/*/mime/struct.Mime.html 41 | -------------------------------------------------------------------------------- /src/concurrency/parallel/rayon-parallel-sort.md: -------------------------------------------------------------------------------- 1 | ## 对 vector 并行排序 2 | 3 | 8 | 9 | [![rayon-badge]][rayon] [![rand-badge]][rand] [![cat-concurrency-badge]][cat-concurrency] 10 | 11 | 本实例对字符串 vector 并行排序。 12 | 13 | 首先,分配空字符串 vector;然后,通过 `par_iter_mut().for_each` 并行对 vector 填充随机值。尽管存在[多种选择][multiple options],可以对可枚举数据类型进行排序,但 [`par_sort_unstable`] 通常比[稳定排序(相同的值排序后相对顺序不变)][stable sorting]算法快。 14 | 15 | ```rust,edition2018 16 | 17 | use rand::{Rng, thread_rng}; 18 | use rand::distributions::Alphanumeric; 19 | use rayon::prelude::*; 20 | 21 | fn main() { 22 | let mut vec = vec![String::new(); 100_000]; 23 | vec.par_iter_mut().for_each(|p| { 24 | let mut rng = thread_rng(); 25 | *p = (0..5).map(|_| rng.sample(&Alphanumeric)).collect() 26 | }); 27 | vec.par_sort_unstable(); 28 | } 29 | ``` 30 | 31 | [`par_sort_unstable`]: https://docs.rs/rayon/*/rayon/slice/trait.ParallelSliceMut.html#method.par_sort_unstable 32 | [multiple options]: https://docs.rs/rayon/*/rayon/slice/trait.ParallelSliceMut.html 33 | [stable sorting]: https://docs.rs/rayon/*/rayon/slice/trait.ParallelSliceMut.html#method.par_sort 34 | -------------------------------------------------------------------------------- /src/concurrency/parallel/rayon-parallel-search.md: -------------------------------------------------------------------------------- 1 | ## 使用给定断言并行搜索项 2 | 3 | 8 | 9 | [![rayon-badge]][rayon] [![cat-concurrency-badge]][cat-concurrency] 10 | 11 | 下面的实例使用 [`rayon::find_any`] 和 [`par_iter`] 并行搜索 vector 集合,以查找满足指定闭包中的断言的元素。 12 | 13 | 如果有多个元素满足 [`rayon::find_any`] 闭包参数中定义的断言,`rayon` 将返回搜索发现的第一个元素,但不一定是 vector 集合的第一个元素。 14 | 15 | 请注意,实例中闭包的参数是对引用的引用(`&&x`)。有关更多详细信息,请参阅关于 [`std::find`] 的讨论。 16 | 17 | ```rust,edition2018 18 | use rayon::prelude::*; 19 | 20 | fn main() { 21 | let v = vec![6, 2, 1, 9, 3, 8, 11]; 22 | 23 | let f1 = v.par_iter().find_any(|&&x| x == 9); 24 | let f2 = v.par_iter().find_any(|&&x| x % 2 == 0 && x > 6); 25 | let f3 = v.par_iter().find_any(|&&x| x > 8); 26 | 27 | assert_eq!(f1, Some(&9)); 28 | assert_eq!(f2, Some(&8)); 29 | assert!(f3 > Some(&8)); 30 | } 31 | ``` 32 | 33 | [`par_iter`]: https://docs.rs/rayon/*/rayon/iter/trait.IntoParallelRefIterator.html#tymethod.par_iter 34 | [`rayon::find_any`]: https://docs.rs/rayon/*/rayon/iter/trait.ParallelIterator.html#method.find_any 35 | [`std::find`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.find 36 | -------------------------------------------------------------------------------- /src/encoding/string/url-encode.md: -------------------------------------------------------------------------------- 1 | ## 将字符串编码为 application/x-www-form-urlencoded 2 | 3 | 8 | 9 | [![url-badge]][url] [![cat-encoding-badge]][cat-encoding] 10 | 11 | 如下实例使用 [`form_urlencoded::byte_serialize`] 将字符串编码为 [application/x-www-form-urlencoded] 表单语法,随后使用 [`form_urlencoded::parse`] 对其进行解码。这两个函数都返回迭代器,然后这些迭代器聚集为 `String`。 12 | 13 | ```rust,edition2018 14 | use url::form_urlencoded::{byte_serialize, parse}; 15 | 16 | fn main() { 17 | let urlencoded: String = byte_serialize("What is ❤?".as_bytes()).collect(); 18 | assert_eq!(urlencoded, "What+is+%E2%9D%A4%3F"); 19 | println!("urlencoded:'{}'", urlencoded); 20 | 21 | let decoded: String = parse(urlencoded.as_bytes()) 22 | .map(|(key, val)| [key, val].concat()) 23 | .collect(); 24 | assert_eq!(decoded, "What is ❤?"); 25 | println!("decoded:'{}'", decoded); 26 | } 27 | ``` 28 | 29 | [`form_urlencoded::byte_serialize`]: https://docs.rs/url/*/url/form_urlencoded/fn.byte_serialize.html 30 | [`form_urlencoded::parse`]: https://docs.rs/url/*/url/form_urlencoded/fn.parse.html 31 | 32 | [application/x-www-form-urlencoded]: https://url.spec.whatwg.org/#application/x-www-form-urlencoded 33 | -------------------------------------------------------------------------------- /src/file/dir/ignore-case.md: -------------------------------------------------------------------------------- 1 | ## 忽略文件名大小写,使用给定模式查找所有文件 2 | 3 | 8 | 9 | [![glob-badge]][glob] [![cat-filesystem-badge]][cat-filesystem] 10 | 11 | 在 `/media/` 目录中查找与正则表达模式 `img_[0-9]*.png` 匹配的所有图像文件。 12 | 13 | 一个自定义 [`MatchOptions`] 结构体被传递给 [`glob_with`] 函数,使全局命令模式下不区分大小写,同时保持其他选项的默认值 [`Default`]。 14 | 15 | > 译者注:`glob` 是 `glob command` 的简写。在 shell 里面,用 `*` 等匹配模式来匹配文件,如:ls src/*.rs。 16 | 17 | ```rust,edition2018,no_run 18 | use error_chain::error_chain; 19 | use glob::{glob_with, MatchOptions}; 20 | 21 | error_chain! { 22 | foreign_links { 23 | Glob(glob::GlobError); 24 | Pattern(glob::PatternError); 25 | } 26 | } 27 | 28 | fn main() -> Result<()> { 29 | let options = MatchOptions { 30 | case_sensitive: false, 31 | ..Default::default() 32 | }; 33 | 34 | for entry in glob_with("/media/img_[0-9]*.png", options)? { 35 | println!("{}", entry?.display()); 36 | } 37 | 38 | Ok(()) 39 | } 40 | ``` 41 | 42 | [`Default`]: https://doc.rust-lang.org/std/default/trait.Default.html 43 | [`glob_with`]: https://docs.rs/glob/*/glob/fn.glob_with.html 44 | [`MatchOptions`]: https://docs.rs/glob/*/glob/struct.MatchOptions.html 45 | -------------------------------------------------------------------------------- /src/science/mathematics/linear_algebra/deserialize-matrix.md: -------------------------------------------------------------------------------- 1 | ## (反)序列化矩阵 2 | 3 | 8 | 9 | [![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science] 10 | 11 | 本实例实现将矩阵序列化为 JSON,以及从 JSON 反序列化出矩阵。序列化由 [`serde_json::to_string`] 处理,[`serde_json::from_str`] 则执行反序列化。 12 | 13 | 请注意:序列化后再反序列化将返回原始矩阵。 14 | 15 | ```rust 16 | extern crate nalgebra; 17 | extern crate serde_json; 18 | 19 | use nalgebra::DMatrix; 20 | 21 | fn main() -> Result<(), std::io::Error> { 22 | let row_slice: Vec = (1..5001).collect(); 23 | let matrix = DMatrix::from_row_slice(50, 100, &row_slice); 24 | 25 | // 序列化矩阵 26 | let serialized_matrix = serde_json::to_string(&matrix)?; 27 | 28 | // 反序列化出矩阵 29 | let deserialized_matrix: DMatrix = serde_json::from_str(&serialized_matrix)?; 30 | 31 | // 验证反序列化出的矩阵 `deserialized_matrix` 等同于原始矩阵 `matrix` 32 | assert!(deserialized_matrix == matrix); 33 | 34 | Ok(()) 35 | } 36 | ``` 37 | 38 | [`serde_json::to_string`]: https://docs.rs/serde_json/*/serde_json/fn.to_string.html 39 | [`serde_json::from_str`]: https://docs.rs/serde_json/*/serde_json/fn.from_str.html 40 | -------------------------------------------------------------------------------- /src/web/mime/filename.md: -------------------------------------------------------------------------------- 1 | ## 从文件名获取 MIME 类型 2 | 3 | 8 | 9 | [![mime-badge]][mime] [![cat-encoding-badge]][cat-encoding] 10 | 11 | 下面的实例展示如何使用 [mime] crate 从给定的文件名返回正确的 MIME 类型。程序将检查文件扩展名并与已知的 MIME 类型列表匹配,返回值为 [`mime:Mime`]。 12 | 13 | ```rust,edition2018 14 | use mime::Mime; 15 | 16 | fn find_mimetype (filename : &String) -> Mime{ 17 | 18 | let parts : Vec<&str> = filename.split('.').collect(); 19 | 20 | let res = match parts.last() { 21 | Some(v) => 22 | match *v { 23 | "png" => mime::IMAGE_PNG, 24 | "jpg" => mime::IMAGE_JPEG, 25 | "json" => mime::APPLICATION_JSON, 26 | &_ => mime::TEXT_PLAIN, 27 | }, 28 | None => mime::TEXT_PLAIN, 29 | }; 30 | return res; 31 | } 32 | 33 | fn main() { 34 | let filenames = vec!("foobar.jpg", "foo.bar", "foobar.png"); 35 | for file in filenames { 36 | let mime = find_mimetype(&file.to_owned()); 37 | println!("MIME for {}: {}", file, mime); 38 | } 39 | 40 | } 41 | ``` 42 | 43 | [`mime:Mime`]: https://docs.rs/mime/*/mime/struct.Mime.html 44 | -------------------------------------------------------------------------------- /src/algorithms/randomness/rand-custom.md: -------------------------------------------------------------------------------- 1 | ## 生成自定义类型随机值 2 | 3 | 8 | 9 | [![rand-badge]][rand] [![cat-science-badge]][cat-science] 10 | 11 | 随机生成一个元组 `(i32, bool, f64)` 和用户定义类型为 `Point` 的变量。为 [`Standard`] 实现 [`Distribution`] trait,以允许随机生成。 12 | 13 | ```rust,edition2018 14 | use rand::Rng; 15 | use rand::distributions::{Distribution, Standard}; 16 | 17 | #[derive(Debug)] 18 | struct Point { 19 | x: i32, 20 | y: i32, 21 | } 22 | 23 | impl Distribution for Standard { 24 | fn sample(&self, rng: &mut R) -> Point { 25 | let (rand_x, rand_y) = rng.gen(); 26 | Point { 27 | x: rand_x, 28 | y: rand_y, 29 | } 30 | } 31 | } 32 | 33 | fn main() { 34 | let mut rng = rand::thread_rng(); 35 | let rand_tuple = rng.gen::<(i32, bool, f64)>(); 36 | let rand_point: Point = rng.gen(); 37 | println!("Random tuple: {:?}", rand_tuple); 38 | println!("Random Point: {:?}", rand_point); 39 | } 40 | ``` 41 | 42 | [`Distribution`]: https://docs.rs/rand/*/rand/distributions/trait.Distribution.html 43 | [`Standard`]: https://docs.rs/rand/*/rand/distributions/struct.Standard.html 44 | -------------------------------------------------------------------------------- /src/compression/tar/tar-compress.md: -------------------------------------------------------------------------------- 1 | ## 压缩目录为 tar 包 2 | 3 | 8 | 9 | [![flate2-badge]][flate2] [![tar-badge]][tar] [![cat-compression-badge]][cat-compression] 10 | 11 | 压缩 `/var/log` 目录内的内容到 `archive.tar.gz` 压缩包中。 12 | 13 | 创建一个用 [`GzEncoder`] 和 [`tar::Builder`] 包裹的 [`File`]。 14 | 15 | 使用 [`Builder::append_dir_all`],将 `/var/log` 目录内的内容递归添加到 `backup/logs` 路径下的归档文件中。在将数据写入压缩包 `archive.tar.gz` 之前,[`GzEncoder`] 负责清晰地将数据压缩。 16 | 17 | ```rust,edition2018,no_run 18 | 19 | use std::fs::File; 20 | use flate2::Compression; 21 | use flate2::write::GzEncoder; 22 | 23 | fn main() -> Result<(), std::io::Error> { 24 | let tar_gz = File::create("archive.tar.gz")?; 25 | let enc = GzEncoder::new(tar_gz, Compression::default()); 26 | let mut tar = tar::Builder::new(enc); 27 | tar.append_dir_all("backup/logs", "/var/log")?; 28 | Ok(()) 29 | } 30 | ``` 31 | 32 | [`Builder::append_dir_all`]: https://docs.rs/tar/*/tar/struct.Builder.html#method.append_dir_all 33 | [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html 34 | [`GzEncoder`]: https://docs.rs/flate2/*/flate2/write/struct.GzEncoder.html 35 | [`tar::Builder`]: https://docs.rs/tar/*/tar/struct.Builder.html 36 | -------------------------------------------------------------------------------- /src/file/read-write/memmap.md: -------------------------------------------------------------------------------- 1 | ## 使用内存映射随机访问文件 2 | 3 | 8 | 9 | [![memmap-badge]][memmap] [![cat-filesystem-badge]][cat-filesystem] 10 | 11 | 使用 [memmap] 创建文件的内存映射,并模拟文件的一些非序列读取。使用内存映射意味着您仅需索引一个切片,而不是使用 [`seek`] 方法来导航整个文件。 12 | 13 | [`Mmap::map`] 函数假定内存映射后的文件没有被另一个进程同时更改,否则会出现[竞态条件][race condition]。 14 | 15 | ```rust,edition2018 16 | use memmap::Mmap; 17 | use std::fs::File; 18 | use std::io::{Write, Error}; 19 | 20 | fn main() -> Result<(), Error> { 21 | # write!(File::create("content.txt")?, "My hovercraft is full of eels!")?; 22 | # 23 | let file = File::open("content.txt")?; 24 | let map = unsafe { Mmap::map(&file)? }; 25 | 26 | let random_indexes = [0, 1, 2, 19, 22, 10, 11, 29]; 27 | assert_eq!(&map[3..13], b"hovercraft"); 28 | let random_bytes: Vec = random_indexes.iter() 29 | .map(|&idx| map[idx]) 30 | .collect(); 31 | assert_eq!(&random_bytes[..], b"My loaf!"); 32 | Ok(()) 33 | } 34 | ``` 35 | 36 | [`Mmap::map`]: https://docs.rs/memmap/*/memmap/struct.Mmap.html#method.map 37 | [`seek`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.seek 38 | 39 | [race condition]: https://baike.baidu.com/item/%E7%AB%9E%E4%BA%89%E5%8D%B1%E5%AE%B3/3525767 40 | -------------------------------------------------------------------------------- /src/development_tools/debugging/config_log/log-env-variable.md: -------------------------------------------------------------------------------- 1 | ## 用自定义环境变量设置日志记录 2 | 3 | 8 | 9 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 10 | 11 | [`Builder`] 配置日志记录。 12 | 13 | [`Builder::parse`] 以 [`RUST_LOG`] 语法的形式解析 `MY_APP_LOG` 环境变量的内容。然后,[`Builder::init`] 初始化记录器。所有这些步骤通常由 [`env_logger::init`] 在内部完成。 14 | 15 | ```rust,edition2018 16 | 17 | use std::env; 18 | use env_logger::Builder; 19 | 20 | fn main() { 21 | Builder::new() 22 | .parse(&env::var("MY_APP_LOG").unwrap_or_default()) 23 | .init(); 24 | 25 | log::info!("informational message"); 26 | log::warn!("warning message"); 27 | log::error!("this is an error {}", "message"); 28 | } 29 | ``` 30 | 31 | [`env_logger::init`]: https://docs.rs/env_logger/*/env_logger/fn.init.html 32 | [`Builder`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html 33 | [`Builder::init`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html#method.init 34 | [`Builder::parse`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html#method.parse 35 | [`RUST_LOG`]: https://docs.rs/env_logger/*/env_logger/#enabling-logging 36 | -------------------------------------------------------------------------------- /src/text/regex/hashtags.md: -------------------------------------------------------------------------------- 1 | ## 从文本提取标签元素唯一的列表 2 | 3 | 8 | 9 | [![regex-badge]][regex] [![lazy_static-badge]][lazy_static] [![cat-text-processing-badge]][cat-text-processing] 10 | 11 | 本实例展示从文本中提取、排序和去除标签列表的重复元素。 12 | 13 | 这里给出的标签正则表达式只捕获以字母开头的拉丁语标签,完整的 [twitter 标签正则表达式][twitter hashtag regex]要复杂得多。 14 | 15 | ```rust,edition2018 16 | use lazy_static::lazy_static; 17 | 18 | use regex::Regex; 19 | use std::collections::HashSet; 20 | 21 | fn extract_hashtags(text: &str) -> HashSet<&str> { 22 | lazy_static! { 23 | static ref HASHTAG_REGEX : Regex = Regex::new( 24 | r"\#[a-zA-Z][0-9a-zA-Z_]*" 25 | ).unwrap(); 26 | } 27 | HASHTAG_REGEX.find_iter(text).map(|mat| mat.as_str()).collect() 28 | } 29 | 30 | fn main() { 31 | let tweet = "Hey #world, I just got my new #dog, say hello to Till. #dog #forever #2 #_ "; 32 | let tags = extract_hashtags(tweet); 33 | assert!(tags.contains("#dog") && tags.contains("#forever") && tags.contains("#world")); 34 | assert_eq!(tags.len(), 3); 35 | } 36 | ``` 37 | 38 | [twitter hashtag regex]: https://github.com/twitter/twitter-text/blob/c9fc09782efe59af4ee82855768cfaf36273e170/java/src/com/twitter/Regex.java#L255 39 | -------------------------------------------------------------------------------- /src/encoding/csv/serialize.md: -------------------------------------------------------------------------------- 1 | ## 将记录序列化为 CSV 2 | 3 | 8 | 9 | [![csv-badge]][csv] [![cat-encoding-badge]][cat-encoding] 10 | 11 | 本实例展示了如何序列化 Rust 元组。[`csv::writer`] 支持从 Rust 类型到 CSV 记录的自动序列化。[`write_record`] 只写入包含字符串数据的简单记录。具有更复杂值(如数字、浮点和选项)的数据使用 [`serialize`] 进行序列化。因为 [`csv::writer`] 使用内部缓冲区,所以在完成时总是显式刷新 [`flush`]。 12 | 13 | ```rust,edition2018 14 | # use error_chain::error_chain; 15 | 16 | use std::io; 17 | # 18 | # error_chain! { 19 | # foreign_links { 20 | # CSVError(csv::Error); 21 | # IOError(std::io::Error); 22 | # } 23 | # } 24 | 25 | fn main() -> Result<()> { 26 | let mut wtr = csv::Writer::from_writer(io::stdout()); 27 | 28 | wtr.write_record(&["Name", "Place", "ID"])?; 29 | 30 | wtr.serialize(("Mark", "Sydney", 87))?; 31 | wtr.serialize(("Ashley", "Dublin", 32))?; 32 | wtr.serialize(("Akshat", "Delhi", 11))?; 33 | 34 | wtr.flush()?; 35 | Ok(()) 36 | } 37 | ``` 38 | 39 | [`csv::Writer`]: https://docs.rs/csv/*/csv/struct.Writer.html 40 | [`flush`]: https://docs.rs/csv/*/csv/struct.Writer.html#method.flush 41 | [`serialize`]: https://docs.rs/csv/*/csv/struct.Writer.html#method.serialize 42 | [`write_record`]: https://docs.rs/csv/*/csv/struct.Writer.html#method.write_record 43 | -------------------------------------------------------------------------------- /src/os/external/continuous.md: -------------------------------------------------------------------------------- 1 | ## 持续处理子进程的输出 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-os-badge]][cat-os] 10 | 11 | 在[运行外部命令并处理-stdout](#运行外部命令并处理-stdout) 实例中,直到外部命令 [`Command`] 完成,stdout 的处理才开始。下面的实例调用 [`Stdio::piped`] 创建管道,并在 [`BufReader`] 被更新后立即读取 `stdout`,持续不断地处理。 12 | 13 | 下面的实例等同于 Unix shell 命令 `journalctl | grep usb`。 14 | 15 | ```rust,edition2018,no_run 16 | use std::process::{Command, Stdio}; 17 | use std::io::{BufRead, BufReader, Error, ErrorKind}; 18 | 19 | fn main() -> Result<(), Error> { 20 | let stdout = Command::new("journalctl") 21 | .stdout(Stdio::piped()) 22 | .spawn()? 23 | .stdout 24 | .ok_or_else(|| Error::new(ErrorKind::Other,"Could not capture standard output."))?; 25 | 26 | let reader = BufReader::new(stdout); 27 | 28 | reader 29 | .lines() 30 | .filter_map(|line| line.ok()) 31 | .filter(|line| line.find("usb").is_some()) 32 | .for_each(|line| println!("{}", line)); 33 | 34 | Ok(()) 35 | } 36 | ``` 37 | 38 | [`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html 39 | [`Command`]: https://doc.rust-lang.org/std/process/struct.Command.html 40 | [`Stdio::piped`]: https://doc.rust-lang.org/std/process/struct.Stdio.html 41 | -------------------------------------------------------------------------------- /src/algorithms/randomness/rand-range.md: -------------------------------------------------------------------------------- 1 | ## 生成范围内随机数 2 | 3 | 8 | 9 | [![rand-badge]][rand] [![cat-science-badge]][cat-science] 10 | 11 | 使用 [`Rng::gen_range`],在半开放的 `[0, 10)` 范围内(不包括 `10`)生成一个随机值。 12 | 13 | ```rust,edition2018 14 | use rand::Rng; 15 | 16 | fn main() { 17 | let mut rng = rand::thread_rng(); 18 | println!("Integer: {}", rng.gen_range(0..10)); 19 | println!("Float: {}", rng.gen_range(0.0..10.0)); 20 | } 21 | ``` 22 | 23 | 使用 [`Uniform`] 模块可以得到[均匀分布][uniform distribution]的值。下述代码和上述代码具有相同的效果,但在相同范围内重复生成数字时,下述代码性能可能会更好。 24 | 25 | ```rust,edition2018 26 | 27 | use rand::distributions::{Distribution, Uniform}; 28 | 29 | fn main() { 30 | let mut rng = rand::thread_rng(); 31 | let die = Uniform::from(1..7); 32 | 33 | loop { 34 | let throw = die.sample(&mut rng); 35 | println!("Roll the die: {}", throw); 36 | if throw == 6 { 37 | break; 38 | } 39 | } 40 | } 41 | ``` 42 | 43 | [`Uniform`]: https://docs.rs/rand/*/rand/distributions/uniform/struct.Uniform.html 44 | [`Rng::gen_range`]: https://doc.rust-lang.org/rand/*/rand/trait.Rng.html#method.gen_range 45 | [uniform distribution]: https://en.wikipedia.org/wiki/Uniform_distribution_(continuous) 46 | -------------------------------------------------------------------------------- /src/database/sqlite/initialization.md: -------------------------------------------------------------------------------- 1 | ## 创建 SQLite 数据库 2 | 3 | 8 | 9 | [![rusqlite-badge]][rusqlite] [![cat-database-badge]][cat-database] 10 | 11 | 使用 `rusqlite` crate 打开 SQLite 数据库连接。Windows 上编译 `rusqlite` crate 请参考[文档][documentation]。 12 | 13 | 如果数据库不存在,[`Connection::open`] 方法将创建它。 14 | 15 | ```rust,edition2018,no_run 16 | use rusqlite::{Connection, Result}; 17 | use rusqlite::NO_PARAMS; 18 | 19 | fn main() -> Result<()> { 20 | let conn = Connection::open("cats.db")?; 21 | 22 | conn.execute( 23 | "create table if not exists cat_colors ( 24 | id integer primary key, 25 | name text not null unique 26 | )", 27 | NO_PARAMS, 28 | )?; 29 | conn.execute( 30 | "create table if not exists cats ( 31 | id integer primary key, 32 | name text not null, 33 | color_id integer not null references cat_colors(id) 34 | )", 35 | NO_PARAMS, 36 | )?; 37 | 38 | Ok(()) 39 | } 40 | ``` 41 | 42 | [`Connection::open`]: https://docs.rs/rusqlite/*/rusqlite/struct.Connection.html#method.open 43 | 44 | [documentation]: https://github.com/jgallagher/rusqlite#user-content-notes-on-building-rusqlite-and-libsqlite3-sys 45 | -------------------------------------------------------------------------------- /src/development_tools/build_tools/cc-bundled-cpp.md: -------------------------------------------------------------------------------- 1 | ## 编译并静态链接到绑定的 C++ 语言库 2 | 3 | 8 | 9 | [![cc-badge]][cc] [![cat-development-tools-badge]][cat-development-tools] 10 | 11 | 链接绑定的 C++ 语言库非常类似于链接绑定的 C 语言库。编译并静态链接绑定的 C++ 库时,与链接绑定的 C 语言库相比有两个核心区别:一是通过构造器方法 [`cpp(true)`][cc-build-cpp] 指定 C++ 编译器;二是通过在 C++ 源文件顶部添加 `extern "C"` 代码段,以防止 C++ 编译器的名称篡改。 12 | 13 | ### `Cargo.toml` 14 | 15 | ```toml 16 | [package] 17 | ... 18 | build = "build.rs" 19 | 20 | [build-dependencies] 21 | cc = "1" 22 | ``` 23 | 24 | ### `build.rs` 25 | 26 | ```rust,edition2018,no_run 27 | fn main() { 28 | cc::Build::new() 29 | .cpp(true) 30 | .file("src/foo.cpp") 31 | .compile("foo"); 32 | } 33 | ``` 34 | 35 | ### `src/foo.cpp` 36 | 37 | ```cpp 38 | extern "C" { 39 | int multiply(int x, int y); 40 | } 41 | 42 | int multiply(int x, int y) { 43 | return x*y; 44 | } 45 | ``` 46 | 47 | ### `src/main.rs` 48 | 49 | ```rust,edition2018,ignore 50 | extern { 51 | fn multiply(x : i32, y : i32) -> i32; 52 | } 53 | 54 | fn main(){ 55 | unsafe { 56 | println!("{}", multiply(5,7)); 57 | } 58 | } 59 | ``` 60 | 61 | [cc-build-cpp]: https://docs.rs/cc/*/cc/struct.Build.html#method.cpp 62 | -------------------------------------------------------------------------------- /src/file/dir/skip-dot.md: -------------------------------------------------------------------------------- 1 | ## 跳过隐藏文件遍历目录 2 | 3 | 8 | 9 | [![walkdir-badge]][walkdir] [![cat-filesystem-badge]][cat-filesystem] 10 | 11 | 递归下行到子目录的过程中,使用 [`filter_entry`] 对目录中的条目传递 `is_not_hidden` 断言,从而跳过隐藏的文件和目录。[`Iterator::filter`] 可应用到要检索的任何目录 [`WalkDir::DirEntry`],即使父目录是隐藏目录。 12 | 13 | 根目录 `"."` 的检索结果,通过在断言 `is_not_hidden` 中使用 [`WalkDir::depth`] 参数生成。 14 | 15 | ```rust,edition2018,no_run 16 | use walkdir::{DirEntry, WalkDir}; 17 | 18 | fn is_not_hidden(entry: &DirEntry) -> bool { 19 | entry 20 | .file_name() 21 | .to_str() 22 | .map(|s| entry.depth() == 0 || !s.starts_with(".")) 23 | .unwrap_or(false) 24 | } 25 | 26 | fn main() { 27 | WalkDir::new(".") 28 | .into_iter() 29 | .filter_entry(|e| is_not_hidden(e)) 30 | .filter_map(|v| v.ok()) 31 | .for_each(|x| println!("{}", x.path().display())); 32 | } 33 | ``` 34 | 35 | [`filter_entry`]: https://docs.rs/walkdir/*/walkdir/struct.IntoIter.html#method.filter_entry 36 | [`Iterator::filter`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter 37 | [`WalkDir::depth`]: https://docs.rs/walkdir/*/walkdir/struct.DirEntry.html#method.depth 38 | [`WalkDir::DirEntry`]: https://docs.rs/walkdir/*/walkdir/struct.DirEntry.html 39 | -------------------------------------------------------------------------------- /src/datetime/parse/format.md: -------------------------------------------------------------------------------- 1 | ## 日期和时间的格式化显示 2 | 3 | 8 | 9 | [![chrono-badge]][chrono] [![cat-date-and-time-badge]][cat-date-and-time] 10 | 11 | 使用 [`Utc::now`] 获取并显示当前 UTC 时间。使用 [`DateTime::to_rfc2822`] 将当前时间格式化为熟悉的 [RFC 2822] 格式,使用 [`DateTime::to_rfc3339`] 将当前时间格式化为熟悉的 [RFC 3339] 格式,也可以使用 [`DateTime::format`] 自定义时间格式。 12 | 13 | ```rust,edition2018 14 | use chrono::{DateTime, Utc}; 15 | 16 | fn main() { 17 | let now: DateTime = Utc::now(); 18 | 19 | println!("UTC now is: {}", now); 20 | println!("UTC now in RFC 2822 is: {}", now.to_rfc2822()); 21 | println!("UTC now in RFC 3339 is: {}", now.to_rfc3339()); 22 | println!("UTC now in a custom format is: {}", now.format("%a %b %e %T %Y")); 23 | } 24 | ``` 25 | 26 | [`DateTime::format`]: https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.format 27 | [`DateTime::to_rfc2822`]: https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.to_rfc2822 28 | [`DateTime::to_rfc3339`]: https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.to_rfc3339 29 | [`Utc::now`]: https://docs.rs/chrono/*/chrono/offset/struct.Utc.html#method.now 30 | 31 | [RFC 2822]: https://www.ietf.org/rfc/rfc2822.txt 32 | [RFC 3339]: https://www.ietf.org/rfc/rfc3339.txt 33 | -------------------------------------------------------------------------------- /src/encoding/complex/endian-byte.md: -------------------------------------------------------------------------------- 1 | ## 以小端模式(低位模式)字节顺序读写整数 2 | 3 | 8 | 9 | [![byteorder-badge]][byteorder] [![cat-encoding-badge]][cat-encoding] 10 | 11 | 字节序 `byteorder` 可以反转结构化数据的有效字节。当通过网络接收信息时,这可能是必要的,例如接收到的字节来自另一个系统。 12 | 13 | ```rust,edition2018 14 | 15 | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; 16 | use std::io::Error; 17 | 18 | #[derive(Default, PartialEq, Debug)] 19 | struct Payload { 20 | kind: u8, 21 | value: u16, 22 | } 23 | 24 | fn main() -> Result<(), Error> { 25 | let original_payload = Payload::default(); 26 | let encoded_bytes = encode(&original_payload)?; 27 | let decoded_payload = decode(&encoded_bytes)?; 28 | assert_eq!(original_payload, decoded_payload); 29 | Ok(()) 30 | } 31 | 32 | fn encode(payload: &Payload) -> Result, Error> { 33 | let mut bytes = vec![]; 34 | bytes.write_u8(payload.kind)?; 35 | bytes.write_u16::(payload.value)?; 36 | Ok(bytes) 37 | } 38 | 39 | fn decode(mut bytes: &[u8]) -> Result { 40 | let payload = Payload { 41 | kind: bytes.read_u8()?, 42 | value: bytes.read_u16::()?, 43 | }; 44 | Ok(payload) 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /src/encoding/csv/filter.md: -------------------------------------------------------------------------------- 1 | ## 筛选匹配断言的 CSV 记录 2 | 3 | 8 | 9 | [![csv-badge]][csv] [![cat-encoding-badge]][cat-encoding] 10 | 11 | _仅仅_ 返回 `data` 中字段(field)与 `query` 匹配的的行。 12 | 13 | ```rust,edition2018 14 | # use error_chain::error_chain; 15 | 16 | use std::io; 17 | # 18 | # error_chain!{ 19 | # foreign_links { 20 | # Io(std::io::Error); 21 | # CsvError(csv::Error); 22 | # } 23 | # } 24 | 25 | fn main() -> Result<()> { 26 | let query = "CA"; 27 | let data = "\ 28 | City,State,Population,Latitude,Longitude 29 | Kenai,AK,7610,60.5544444,-151.2583333 30 | Oakman,AL,,33.7133333,-87.3886111 31 | Sandfort,AL,,32.3380556,-85.2233333 32 | West Hollywood,CA,37031,34.0900000,-118.3608333"; 33 | 34 | let mut rdr = csv::ReaderBuilder::new().from_reader(data.as_bytes()); 35 | let mut wtr = csv::Writer::from_writer(io::stdout()); 36 | 37 | wtr.write_record(rdr.headers()?)?; 38 | 39 | for result in rdr.records() { 40 | let record = result?; 41 | if record.iter().any(|field| field == query) { 42 | wtr.write_record(&record)?; 43 | } 44 | } 45 | 46 | wtr.flush()?; 47 | Ok(()) 48 | } 49 | ``` 50 | 51 | _免责声明:此实例改编自[csv crate 教程](https://docs.rs/csv/*/csv/tutorial/index.html#filter-by-search)_。 52 | -------------------------------------------------------------------------------- /src/algorithms/randomness/rand-dist.md: -------------------------------------------------------------------------------- 1 | ## 生成给定分布随机数 2 | 3 | 8 | 9 | [![rand_distr-badge]][rand_distr] [![cat-science-badge]][cat-science] 10 | 11 | 默认情况下,随机数在 `rand` crate 中是[均匀分布][uniform distribution]。[`rand_distr`] crate 提供其它的分布类型。如要使用,首先实例化一个分布,然后在随机数生成器 [`rand::Rng`] 的帮助下,使用 [`Distribution::sample`] 从该分布中进行采样。 12 | 13 | 关于更多信息,阅读[可用分布文档][rand-distributions]。如下是一个使用[`正态(Normal)`][`Normal`]分布的实例。 14 | 15 | ```rust,edition2018,ignore 16 | use rand_distr::{Distribution, Normal, NormalError}; 17 | use rand::thread_rng; 18 | 19 | fn main() -> Result<(), NormalError> { 20 | let mut rng = thread_rng(); 21 | let normal = Normal::new(2.0, 3.0)?; 22 | let v = normal.sample(&mut rng); 23 | println!("{} is from a N(2, 9) distribution", v); 24 | Ok(()) 25 | } 26 | ``` 27 | 28 | [`Distribution::sample`]: https://docs.rs/rand/*/rand/distributions/trait.Distribution.html#tymethod.sample 29 | [`Normal`]: https://docs.rs/rand_distr/*/rand_distr/struct.Normal.html 30 | [`rand::Rng`]: https://docs.rs/rand/*/rand/trait.Rng.html 31 | [`rand_distr`]: https://docs.rs/rand_distr/*/rand_distr/index.html 32 | [rand-distributions]: https://docs.rs/rand_distr/*/rand_distr/index.html 33 | [uniform distribution]: https://en.wikipedia.org/wiki/Uniform_distribution_(continuous) 34 | -------------------------------------------------------------------------------- /src/datetime/duration/timezone.md: -------------------------------------------------------------------------------- 1 | ## 时间的时区转换 2 | 3 | 8 | 9 | [![chrono-badge]][chrono] [![cat-date-and-time-badge]][cat-date-and-time] 10 | 11 | 使用 [`offset::Local::now`] 获取本地时间并显示,然后使用 [`DateTime::from_utc`] 结构体方法将其转换为 UTC 标准格式。最后,使用 [`offset::FixedOffset`] 结构体,可以将 UTC 时间转换为 UTC+8 和 UTC-2。 12 | 13 | ```rust,edition2018 14 | 15 | use chrono::{DateTime, FixedOffset, Local, Utc}; 16 | 17 | fn main() { 18 | let local_time = Local::now(); 19 | let utc_time = DateTime::::from_utc(local_time.naive_utc(), Utc); 20 | let china_timezone = FixedOffset::east(8 * 3600); 21 | let rio_timezone = FixedOffset::west(2 * 3600); 22 | println!("Local time now is {}", local_time); 23 | println!("UTC time now is {}", utc_time); 24 | println!( 25 | "Time in Hong Kong now is {}", 26 | utc_time.with_timezone(&china_timezone) 27 | ); 28 | println!("Time in Rio de Janeiro now is {}", utc_time.with_timezone(&rio_timezone)); 29 | } 30 | ``` 31 | 32 | [`DateTime::from_utc`]:https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.from_utc 33 | [`offset::FixedOffset`]: https://docs.rs/chrono/*/chrono/offset/struct.FixedOffset.html 34 | [`offset::Local::now`]: https://docs.rs/chrono/*/chrono/offset/struct.Local.html#method.now 35 | -------------------------------------------------------------------------------- /src/development_tools/debugging/log/log-syslog.md: -------------------------------------------------------------------------------- 1 | ## 记录到 Unix 系统日志 2 | 3 | 8 | 9 | [![log-badge]][log] [![syslog-badge]][syslog] [![cat-debugging-badge]][cat-debugging] 10 | 11 | 本实例实现将信息记录到 [UNIX syslog]。使用 [`syslog::init`] 初始化记录器后端。[`syslog::Facility`] 记录提交日志项分类的程序,[`log::LevelFilter`] 表示欲记录日志的等级,`Option<&str>` 定义应用程序名称(可选)。 12 | 13 | ```rust,edition2018 14 | # #[cfg(target_os = "linux")] 15 | # #[cfg(target_os = "linux")] 16 | use syslog::{Facility, Error}; 17 | 18 | # #[cfg(target_os = "linux")] 19 | fn main() -> Result<(), Error> { 20 | syslog::init(Facility::LOG_USER, 21 | log::LevelFilter::Debug, 22 | Some("My app name"))?; 23 | log::debug!("this is a debug {}", "message"); 24 | log::error!("this is an error!"); 25 | Ok(()) 26 | } 27 | 28 | # #[cfg(not(target_os = "linux"))] 29 | # fn main() { 30 | # println!("So far, only Linux systems are supported."); 31 | # } 32 | ``` 33 | 34 | [`log::LevelFilter`]: https://docs.rs/log/*/log/enum.LevelFilter.html 35 | [`syslog::Facility`]: https://docs.rs/syslog/*/syslog/enum.Facility.html 36 | [`syslog::init`]: https://docs.rs/syslog/*/syslog/fn.init.html 37 | 38 | [UNIX syslog]: https://www.gnu.org/software/libc/manual/html_node/Overview-of-Syslog.html 39 | -------------------------------------------------------------------------------- /src/concurrency/thread/crossbeam-spawn.md: -------------------------------------------------------------------------------- 1 | ## 生成短期线程 2 | 3 | 8 | 9 | [![crossbeam-badge]][crossbeam] [![cat-concurrency-badge]][cat-concurrency] 10 | 11 | 本实例使用 [crossbeam] crate 为并发和并行编程提供了数据结构和函数。[`Scope::spawn`] 生成一个新的作用域线程,该线程确保传入 [`crossbeam::scope`] 函数的闭包在返回之前终止,这意味着您可以从调用的函数中引用数据。 12 | 13 | 本实例将数组一分为二,并在不同的线程中并行计算。 14 | 15 | ```rust,edition2018 16 | fn main() { 17 | let arr = &[1, 25, -4, 10]; 18 | let max = find_max(arr); 19 | assert_eq!(max, Some(25)); 20 | } 21 | 22 | fn find_max(arr: &[i32]) -> Option { 23 | const THRESHOLD: usize = 2; 24 | 25 | if arr.len() <= THRESHOLD { 26 | return arr.iter().cloned().max(); 27 | } 28 | 29 | let mid = arr.len() / 2; 30 | let (left, right) = arr.split_at(mid); 31 | 32 | crossbeam::scope(|s| { 33 | let thread_l = s.spawn(|_| find_max(left)); 34 | let thread_r = s.spawn(|_| find_max(right)); 35 | 36 | let max_l = thread_l.join().unwrap()?; 37 | let max_r = thread_r.join().unwrap()?; 38 | 39 | Some(max_l.max(max_r)) 40 | }).unwrap() 41 | } 42 | ``` 43 | 44 | [`crossbeam::scope`]: https://docs.rs/crossbeam/*/crossbeam/fn.scope.html 45 | [`Scope::spawn`]: https://docs.rs/crossbeam/*/crossbeam/thread/struct.Scope.html#method.spawn 46 | -------------------------------------------------------------------------------- /src/database.md: -------------------------------------------------------------------------------- 1 | # 数据库 2 | 3 | 8 | 9 | ## SQLite 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [创建 SQLite 数据库][ex-sqlite-initialization] | [![rusqlite-badge]][rusqlite] | [![cat-database-badge]][cat-database] | 14 | | [数据插入和查询][ex-sqlite-insert-select] | [![rusqlite-badge]][rusqlite] | [![cat-database-badge]][cat-database] | 15 | | [事务处理][ex-sqlite-transactions] | [![rusqlite-badge]][rusqlite] | [![cat-database-badge]][cat-database] | 16 | 17 | ## 使用 Postgres 18 | 19 | | 实例名称 | Crates | 类别 | 20 | |--------|--------|------------| 21 | | [Postgres 数据库中创建表][ex-postgres-create-tables] | [![postgres-badge]][postgres] | [![cat-database-badge]][cat-database] | 22 | | [数据插入和查询][ex-postgres-insert-query-data] | [![postgres-badge]][postgres] | [![cat-database-badge]][cat-database] | 23 | | [数据聚合][ex-postgres-aggregate-data] | [![postgres-badge]][postgres] | [![cat-database-badge]][cat-database] | 24 | 25 | [ex-sqlite-initialization]: database/sqlite.md#创建-sqlite-数据库 26 | [ex-sqlite-insert-select]: database/sqlite.md#数据插入和查询 27 | [ex-sqlite-transactions]: database/sqlite.md#事务处理 28 | 29 | [ex-postgres-create-tables]: database/postgres.md#postgres-数据库中创建表 30 | [ex-postgres-insert-query-data]: database/postgres.md#数据插入和查询 31 | [ex-postgres-aggregate-data]: database/postgres.md#数据聚合 32 | 33 | {{#include links.md}} 34 | -------------------------------------------------------------------------------- /src/science/mathematics/linear_algebra/multiply-scalar-vector-matrix.md: -------------------------------------------------------------------------------- 1 | ## 标量、vector、矩阵相乘 2 | 3 | 8 | 9 | [![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science] 10 | 11 | 使用 [`ndarray::arr1`] 创建一维(1-D)数组(vector),使用 [`ndarray::arr2`] 创建二维(2-D)数组(矩阵)。 12 | 13 | 首先,一个标量乘以一个 vector 得到另一个 vector。然后,使用 [`ndarray::Array2::dot`] 将矩阵乘以新的 vector(矩阵相乘使用 `dot` 函数,而 `*` 运算符执行元素方式的乘法)。 14 | 15 | 在 `ndarray` crate 中,根据上下文,一维数组可以解释为行 vector 或列 vector。如果 vector 表示的方向很重要,则必须使用只有一行或一列的二维(2-D)数组。在本实例中,vector 是右侧的一维(1-D)数组,因此 `dot` 函数将其处理为列 vector。 16 | 17 | ```rust,edition2018 18 | use ndarray::{arr1, arr2, Array1}; 19 | 20 | fn main() { 21 | let scalar = 4; 22 | 23 | let vector = arr1(&[1, 2, 3]); 24 | 25 | let matrix = arr2(&[[4, 5, 6], 26 | [7, 8, 9]]); 27 | 28 | let new_vector: Array1<_> = scalar * vector; 29 | println!("{}", new_vector); 30 | 31 | let new_matrix = matrix.dot(&new_vector); 32 | println!("{}", new_matrix); 33 | } 34 | ``` 35 | 36 | [`ndarray::arr1`]: https://docs.rs/ndarray/*/ndarray/fn.arr1.html 37 | [`ndarray::arr2`]: https://docs.rs/ndarray/*/ndarray/fn.arr2.html 38 | [`ndarray::Array2::dot`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.dot-1 -------------------------------------------------------------------------------- /src/file/dir/loops.md: -------------------------------------------------------------------------------- 1 | ## 查找给定路径的循环 2 | 3 | 8 | 9 | [![same_file-badge]][same_file] [![cat-filesystem-badge]][cat-filesystem] 10 | 11 | 使用 [`same_file::is_same_file`] 检测给定路径的循环。例如,可以通过软连接(符号链接)在 Unix 系统上创建循环: 12 | 13 | ```bash 14 | mkdir -p /tmp/foo/bar/baz 15 | ln -s /tmp/foo/ /tmp/foo/bar/baz/qux 16 | ``` 17 | 18 | 下面的实例将断言存在一个循环。 19 | 20 | ```rust,edition2018,no_run 21 | use std::io; 22 | use std::path::{Path, PathBuf}; 23 | use same_file::is_same_file; 24 | 25 | fn contains_loop>(path: P) -> io::Result> { 26 | let path = path.as_ref(); 27 | let mut path_buf = path.to_path_buf(); 28 | while path_buf.pop() { 29 | if is_same_file(&path_buf, path)? { 30 | return Ok(Some((path_buf, path.to_path_buf()))); 31 | } else if let Some(looped_paths) = contains_loop(&path_buf)? { 32 | return Ok(Some(looped_paths)); 33 | } 34 | } 35 | return Ok(None); 36 | } 37 | 38 | fn main() { 39 | assert_eq!( 40 | contains_loop("/tmp/foo/bar/baz/qux/bar/baz").unwrap(), 41 | Some(( 42 | PathBuf::from("/tmp/foo"), 43 | PathBuf::from("/tmp/foo/bar/baz/qux") 44 | )) 45 | ); 46 | } 47 | ``` 48 | 49 | [`same_file::is_same_file`]: https://docs.rs/same-file/*/same_file/fn.is_same_file.html 50 | -------------------------------------------------------------------------------- /src/file/read-write/same-file.md: -------------------------------------------------------------------------------- 1 | ## 避免读取写入同一文件 2 | 3 | 8 | 9 | [![same_file-badge]][same_file] [![cat-filesystem-badge]][cat-filesystem] 10 | 11 | 对文件使用 [`same_file::Handle`] 结构体,可以测试文件句柄是否等同。在本实例中,将对要读取和写入的文件句柄进行相等性测试。 12 | 13 | ```rust,edition2018,no_run 14 | use same_file::Handle; 15 | use std::fs::File; 16 | use std::io::{BufRead, BufReader, Error, ErrorKind}; 17 | use std::path::Path; 18 | 19 | fn main() -> Result<(), Error> { 20 | let path_to_read = Path::new("new.txt"); 21 | 22 | let stdout_handle = Handle::stdout()?; 23 | let handle = Handle::from_path(path_to_read)?; 24 | 25 | if stdout_handle == handle { 26 | return Err(Error::new( 27 | ErrorKind::Other, 28 | "You are reading and writing to the same file", 29 | )); 30 | } else { 31 | let file = File::open(&path_to_read)?; 32 | let file = BufReader::new(file); 33 | for (num, line) in file.lines().enumerate() { 34 | println!("{} : {}", num, line?.to_uppercase()); 35 | } 36 | } 37 | 38 | Ok(()) 39 | } 40 | ``` 41 | 42 | ```bash 43 | cargo run 44 | ``` 45 | 显示文件 new.txt 的内容。 46 | 47 | ```bash 48 | cargo run >> ./new.txt 49 | ``` 50 | 报错,因为是同一文件。 51 | 52 | [`same_file::Handle`]: https://docs.rs/same-file/*/same_file/struct.Handle.html 53 | -------------------------------------------------------------------------------- /src/os.md: -------------------------------------------------------------------------------- 1 | # 操作系统 2 | 3 | 8 | 9 | ## 外部命令 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [运行外部命令并处理 stdout][ex-parse-subprocess-output] | [![regex-badge]][regex] | [![cat-os-badge]][cat-os] [![cat-text-processing-badge]][cat-text-processing] | 14 | | [运行传递 stdin 的外部命令,并检查错误代码][ex-parse-subprocess-input] | [![regex-badge]][regex] | [![cat-os-badge]][cat-os] [![cat-text-processing-badge]][cat-text-processing] | 15 | | [运行管道传输的外部命令][ex-run-piped-external-commands] | [![std-badge]][std] | [![cat-os-badge]][cat-os] | 16 | | [将子进程的 stdout 和 stderr 重定向到同一个文件][ex-redirect-stdout-stderr-same-file] | [![std-badge]][std] | [![cat-os-badge]][cat-os] | 17 | | [持续处理子进程的输出][ex-continuous-process-output] | [![std-badge]][std] | [![cat-os-badge]][cat-os][![cat-text-processing-badge]][cat-text-processing] | 18 | | [读取环境变量][ex-read-env-variable] | [![std-badge]][std] | [![cat-os-badge]][cat-os] | 19 | 20 | 21 | [ex-parse-subprocess-output]: os/external.md#运行外部命令并处理-stdout 22 | [ex-parse-subprocess-input]: os/external.md#运行传递-stdin-的外部命令并检查错误代码 23 | [ex-run-piped-external-commands]: os/external.md#运行管道传输的外部命令 24 | [ex-redirect-stdout-stderr-same-file]: os/external.md#将子进程的-stdout-和-stderr-重定向到同一个文件 25 | [ex-continuous-process-output]: os/external.md#持续处理子进程的输出 26 | [ex-read-env-variable]: os/external.md#读取环境变量 27 | 28 | {{#include links.md}} 29 | -------------------------------------------------------------------------------- /src/development_tools/debugging/log/log-custom-logger.md: -------------------------------------------------------------------------------- 1 | ## 使用自定义日志记录器记录信息 2 | 3 | 8 | 9 | [![log-badge]][log] [![cat-debugging-badge]][cat-debugging] 10 | 11 | 本实例实现一个打印到 stdout 的自定义记录器 `ConsoleLogger`。为了使用日志宏,`ConsoleLogger` 实现了 [`log::Log`] trait,通过 [`log::set_logger`] 安置。 12 | 13 | ```rust,edition2018 14 | use log::{Record, Level, Metadata, LevelFilter, SetLoggerError}; 15 | 16 | static CONSOLE_LOGGER: ConsoleLogger = ConsoleLogger; 17 | 18 | struct ConsoleLogger; 19 | 20 | impl log::Log for ConsoleLogger { 21 | fn enabled(&self, metadata: &Metadata) -> bool { 22 | metadata.level() <= Level::Info 23 | } 24 | 25 | fn log(&self, record: &Record) { 26 | if self.enabled(record.metadata()) { 27 | println!("Rust says: {} - {}", record.level(), record.args()); 28 | } 29 | } 30 | 31 | fn flush(&self) {} 32 | } 33 | 34 | fn main() -> Result<(), SetLoggerError> { 35 | log::set_logger(&CONSOLE_LOGGER)?; 36 | log::set_max_level(LevelFilter::Info); 37 | 38 | log::info!("hello log"); 39 | log::warn!("warning"); 40 | log::error!("oops"); 41 | Ok(()) 42 | } 43 | ``` 44 | 45 | [`log::Log`]: https://docs.rs/log/*/log/trait.Log.html 46 | [`log::set_logger`]: https://docs.rs/log/*/log/fn.set_logger.html 47 | -------------------------------------------------------------------------------- /src/concurrency/thread/crossbeam-spsc.md: -------------------------------------------------------------------------------- 1 | # 在两个线程间传递数据 2 | 3 | 8 | 9 | [![crossbeam-badge]][crossbeam] [![cat-concurrency-badge]][cat-concurrency] 10 | 11 | 这个实例示范了在单生产者、单消费者(SPSC)环境中使用 [crossbeam-channel]。我们构建的[生成短期线程](#生成短期线程)实例中,使用 [`crossbeam::scope`] 和 [`Scope::spawn`] 来管理生产者线程。在两个线程之间,使用 [`crossbeam_channel::unbounded`] 信道交换数据,这意味着可存储消息的数量没有限制。生产者线程在消息之间休眠半秒。 12 | 13 | ```rust,edition2018 14 | 15 | use std::{thread, time}; 16 | use crossbeam_channel::unbounded; 17 | 18 | fn main() { 19 | let (snd, rcv) = unbounded(); 20 | let n_msgs = 5; 21 | crossbeam::scope(|s| { 22 | s.spawn(|_| { 23 | for i in 0..n_msgs { 24 | snd.send(i).unwrap(); 25 | thread::sleep(time::Duration::from_millis(100)); 26 | } 27 | }); 28 | }).unwrap(); 29 | for _ in 0..n_msgs { 30 | let msg = rcv.recv().unwrap(); 31 | println!("Received {}", msg); 32 | } 33 | } 34 | ``` 35 | 36 | [crossbeam-channel]: https://docs.rs/crate/crossbeam-channel/ 37 | [`crossbeam::scope`]: https://docs.rs/crossbeam/*/crossbeam/fn.scope.html 38 | [`Scope::spawn`]: https://docs.rs/crossbeam/*/crossbeam/thread/struct.Scope.html#method.spawn 39 | [`crossbeam_channel::unbounded`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.unbounded.html 40 | -------------------------------------------------------------------------------- /src/database/postgres/create_tables.md: -------------------------------------------------------------------------------- 1 | ## Postgres 数据库中创建表 2 | 3 | 8 | 9 | [![postgres-badge]][postgres] [![cat-database-badge]][cat-database] 10 | 11 | Postgres 数据库中,使用 [`postgres`] crate 创建表。 12 | 13 | [`Client::connect`] 用于连接到现有数据库。本实例中使用 `Client::connect` 格式化连接数据库的 URL 字符串。假设存在一个数据库:名为 `library`,用户名为 `postgres`,密码为 `postgres`。 14 | 15 | ```rust,edition2018,no_run 16 | use postgres::{Client, NoTls, Error}; 17 | 18 | fn main() -> Result<(), Error> { 19 | let mut client = Client::connect("postgresql://postgres:postgres@localhost/library", NoTls)?; 20 | 21 | client.batch_execute(" 22 | CREATE TABLE IF NOT EXISTS author ( 23 | id SERIAL PRIMARY KEY, 24 | name VARCHAR NOT NULL, 25 | country VARCHAR NOT NULL 26 | ) 27 | ")?; 28 | 29 | client.batch_execute(" 30 | CREATE TABLE IF NOT EXISTS book ( 31 | id SERIAL PRIMARY KEY, 32 | title VARCHAR NOT NULL, 33 | author_id INTEGER NOT NULL REFERENCES author 34 | ) 35 | ")?; 36 | 37 | Ok(()) 38 | 39 | } 40 | ``` 41 | 42 | [`postgres`]: https://docs.rs/postgres/0.17.2/postgres/ 43 | [`Client::connect`]: https://docs.rs/postgres/0.17.2/postgres/struct.Client.html#method.connect 44 | -------------------------------------------------------------------------------- /src/concurrency/parallel/rayon-any-all.md: -------------------------------------------------------------------------------- 1 | ## 并行测试集合中任意或所有的元素是否匹配给定断言 2 | 3 | 8 | 9 | [![rayon-badge]][rayon] [![cat-concurrency-badge]][cat-concurrency] 10 | 11 | 这个实例示范如何使用 [`rayon::any`] 和 [`rayon::all`] 方法,这两个方法是分别与 [`std::any`] 和 [`std::all`] 相对应的并行方法。[`rayon::any`] 并行检查迭代器的任意元素是否与断言匹配,并在找到一个匹配的元素时就返回。[`rayon::all`] 并行检查迭代器的所有元素是否与断言匹配,并在找到不匹配的元素时立即返回。 12 | 13 | ```rust,edition2018 14 | use rayon::prelude::*; 15 | 16 | fn main() { 17 | let mut vec = vec![2, 4, 6, 8]; 18 | 19 | assert!(!vec.par_iter().any(|n| (*n % 2) != 0)); 20 | assert!(vec.par_iter().all(|n| (*n % 2) == 0)); 21 | assert!(!vec.par_iter().any(|n| *n > 8 )); 22 | assert!(vec.par_iter().all(|n| *n <= 8 )); 23 | 24 | vec.push(9); 25 | 26 | assert!(vec.par_iter().any(|n| (*n % 2) != 0)); 27 | assert!(!vec.par_iter().all(|n| (*n % 2) == 0)); 28 | assert!(vec.par_iter().any(|n| *n > 8 )); 29 | assert!(!vec.par_iter().all(|n| *n <= 8 )); 30 | } 31 | ``` 32 | 33 | [`rayon::all`]: https://docs.rs/rayon/*/rayon/iter/trait.ParallelIterator.html#method.all 34 | [`rayon::any`]: https://docs.rs/rayon/*/rayon/iter/trait.ParallelIterator.html#method.any 35 | [`std::all`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.all 36 | [`std::any`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.any 37 | -------------------------------------------------------------------------------- /src/database/postgres/aggregate_data.md: -------------------------------------------------------------------------------- 1 | ## 数据聚合 2 | 3 | 8 | 9 | [![postgres-badge]][postgres] [![cat-database-badge]][cat-database] 10 | 11 | 下述实例按照降序列出了[`美国纽约州现代艺术博物馆`][`Museum of Modern Art`]数据库中首批 7999 位艺术家的国籍。 12 | 13 | ```rust,edition2018,no_run 14 | use postgres::{Client, Error, NoTls}; 15 | 16 | struct Nation { 17 | nationality: String, 18 | count: i64, 19 | } 20 | 21 | fn main() -> Result<(), Error> { 22 | let mut client = Client::connect( 23 | "postgresql://postgres:postgres@127.0.0.1/moma", 24 | NoTls, 25 | )?; 26 | 27 | for row in client.query 28 | ("SELECT nationality, COUNT(nationality) AS count 29 | FROM artists GROUP BY nationality ORDER BY count DESC", &[])? { 30 | 31 | let (nationality, count) : (Option, Option) 32 | = (row.get (0), row.get (1)); 33 | 34 | if nationality.is_some () && count.is_some () { 35 | 36 | let nation = Nation{ 37 | nationality: nationality.unwrap(), 38 | count: count.unwrap(), 39 | }; 40 | println!("{} {}", nation.nationality, nation.count); 41 | 42 | } 43 | } 44 | 45 | Ok(()) 46 | } 47 | ``` 48 | 49 | [`Museum of Modern Art`]: https://github.com/MuseumofModernArt/collection/blob/master/Artists.csv 50 | -------------------------------------------------------------------------------- /src/encoding/complex/json.md: -------------------------------------------------------------------------------- 1 | ## 对非结构化 JSON 序列化和反序列化 2 | 3 | 8 | 9 | [![serde-json-badge]][serde-json] [![cat-encoding-badge]][cat-encoding] 10 | 11 | [`serde_json`] crate 提供了 [`from_str`] 函数来解析 JSON 切片 `&str`。 12 | 13 | 非结构化 JSON 可以被解析为一个通用的 [`serde_json::Value`] 类型,该类型能够表示任何有效的 JSON 数据。 14 | 15 | 下面的实例展示如何解析 JSON 切片 `&str`,期望值被 [`json!`] 宏声明。 16 | 17 | ```rust,edition2018 18 | use serde_json::json; 19 | use serde_json::{Value, Error}; 20 | 21 | fn main() -> Result<(), Error> { 22 | let j = r#"{ 23 | "userid": 103609, 24 | "verified": true, 25 | "access_privileges": [ 26 | "user", 27 | "admin" 28 | ] 29 | }"#; 30 | 31 | let parsed: Value = serde_json::from_str(j)?; 32 | 33 | let expected = json!({ 34 | "userid": 103609, 35 | "verified": true, 36 | "access_privileges": [ 37 | "user", 38 | "admin" 39 | ] 40 | }); 41 | 42 | assert_eq!(parsed, expected); 43 | 44 | Ok(()) 45 | } 46 | ``` 47 | 48 | [`from_str`]: https://docs.serde.rs/serde_json/fn.from_str.html 49 | [`json!`]: https://docs.serde.rs/serde_json/macro.json.html 50 | [`serde_json`]: https://docs.serde.rs/serde_json/ 51 | [`serde_json::Value`]: https://docs.serde.rs/serde_json/enum.Value.html 52 | -------------------------------------------------------------------------------- /theme/highlight.css: -------------------------------------------------------------------------------- 1 | /* Base16 Atelier Dune Light - Theme */ 2 | /* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) */ 3 | /* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ 4 | 5 | /* Atelier-Dune Comment */ 6 | .hljs-comment, 7 | .hljs-quote { 8 | color: #AAA; 9 | } 10 | 11 | /* Atelier-Dune Red */ 12 | .hljs-variable, 13 | .hljs-template-variable, 14 | .hljs-attribute, 15 | .hljs-tag, 16 | .hljs-name, 17 | .hljs-regexp, 18 | .hljs-link, 19 | .hljs-name, 20 | .hljs-selector-id, 21 | .hljs-selector-class { 22 | color: #d73737; 23 | } 24 | 25 | /* Atelier-Dune Orange */ 26 | .hljs-number, 27 | .hljs-meta, 28 | .hljs-built_in, 29 | .hljs-builtin-name, 30 | .hljs-literal, 31 | .hljs-type, 32 | .hljs-params { 33 | color: #b65611; 34 | } 35 | 36 | /* Atelier-Dune Green */ 37 | .hljs-string, 38 | .hljs-symbol, 39 | .hljs-bullet { 40 | color: #60ac39; 41 | } 42 | 43 | /* Atelier-Dune Blue */ 44 | .hljs-title, 45 | .hljs-section { 46 | color: #6684e1; 47 | } 48 | 49 | /* Atelier-Dune Purple */ 50 | .hljs-keyword, 51 | .hljs-selector-tag { 52 | color: #b854d4; 53 | } 54 | 55 | .hljs { 56 | display: block; 57 | overflow-x: auto; 58 | background: #f1f1f1; 59 | color: #6e6b5e; 60 | padding: 0.5em; 61 | } 62 | 63 | .hljs-emphasis { 64 | font-style: italic; 65 | } 66 | 67 | .hljs-strong { 68 | font-weight: bold; 69 | } 70 | 71 | .hljs-addition { 72 | color: #22863a; 73 | background-color: #f0fff4; 74 | } 75 | 76 | .hljs-deletion { 77 | color: #b31d28; 78 | background-color: #ffeef0; 79 | } 80 | -------------------------------------------------------------------------------- /src/file/read-write/read-file.md: -------------------------------------------------------------------------------- 1 | ## 读取文件的字符串行 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-filesystem-badge]][cat-filesystem] 10 | 11 | 我们向文件写入三行信息,然后使用 [`BufRead::lines`] 创建的迭代器 [`Lines`] 读取文件,一次读回一行。[`File`] 模块实现了提供 [`BufReader`] 结构体的 [`Read`] trait。[`File::create`] 打开文件 [`File`] 进行写入,[`File::open`] 则进行读取。 12 | 13 | ```rust,edition2018 14 | use std::fs::File; 15 | use std::io::{Write, BufReader, BufRead, Error}; 16 | 17 | fn main() -> Result<(), Error> { 18 | let path = "lines.txt"; 19 | 20 | let mut output = File::create(path)?; 21 | write!(output, "Rust\n💖\nFun")?; 22 | 23 | let input = File::open(path)?; 24 | let buffered = BufReader::new(input); 25 | 26 | for line in buffered.lines() { 27 | println!("{}", line?); 28 | } 29 | 30 | Ok(()) 31 | } 32 | ``` 33 | 34 | [`BufRead::lines`]: https://doc.rust-lang.org/std/io/trait.BufRead.html#method.lines 35 | [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html 36 | [`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html 37 | [`File::create`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.create 38 | [`File::open`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.open 39 | [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html 40 | [`Lines`]: https://doc.rust-lang.org/std/io/struct.Lines.html 41 | [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html 42 | -------------------------------------------------------------------------------- /src/concurrency/thread/global-mut-state.md: -------------------------------------------------------------------------------- 1 | ## 保持全局可变状态 2 | 3 | 8 | 9 | [![lazy_static-badge]][lazy_static] [![cat-rust-patterns-badge]][cat-rust-patterns] 10 | 11 | 使用 [lazy_static] 声明全局状态。[lazy_static] 创建了一个全局可用的 `static ref`,它需要 [`Mutex`] 来允许变化(请参阅 [`RwLock`])。在 [`Mutex`] 的包裹下,保证了状态不能被多个线程同时访问,从而防止出现争用情况。必须获取 [`MutexGuard`],方可读取或更改存储在 [`Mutex`] 中的值。 12 | 13 | ```rust,edition2018 14 | # use error_chain::error_chain; 15 | use lazy_static::lazy_static; 16 | use std::sync::Mutex; 17 | # 18 | # error_chain!{ } 19 | 20 | lazy_static! { 21 | static ref FRUIT: Mutex> = Mutex::new(Vec::new()); 22 | } 23 | 24 | fn insert(fruit: &str) -> Result<()> { 25 | let mut db = FRUIT.lock().map_err(|_| "Failed to acquire MutexGuard")?; 26 | db.push(fruit.to_string()); 27 | Ok(()) 28 | } 29 | 30 | fn main() -> Result<()> { 31 | insert("apple")?; 32 | insert("orange")?; 33 | insert("peach")?; 34 | { 35 | let db = FRUIT.lock().map_err(|_| "Failed to acquire MutexGuard")?; 36 | 37 | db.iter().enumerate().for_each(|(i, item)| println!("{}: {}", i, item)); 38 | } 39 | insert("grape")?; 40 | Ok(()) 41 | } 42 | ``` 43 | 44 | [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html 45 | [`MutexGuard`]: https://doc.rust-lang.org/std/sync/struct.MutexGuard.html 46 | [`RwLock`]: https://doc.rust-lang.org/std/sync/struct.RwLock.html 47 | -------------------------------------------------------------------------------- /src/datetime/parse/current.md: -------------------------------------------------------------------------------- 1 | ## 检查日期和时间 2 | 3 | 8 | 9 | [![chrono-badge]][chrono] [![cat-date-and-time-badge]][cat-date-and-time] 10 | 11 | 通过 [`Timelike`] 获取当前 UTC [`DateTime`] 及其时/分/秒,通过 [`Datelike`] 获取其年/月/日/工作日。 12 | 13 | ```rust,edition2018 14 | use chrono::{Datelike, Timelike, Utc}; 15 | 16 | fn main() { 17 | let now = Utc::now(); 18 | 19 | let (is_pm, hour) = now.hour12(); 20 | println!( 21 | "The current UTC time is {:02}:{:02}:{:02} {}", 22 | hour, 23 | now.minute(), 24 | now.second(), 25 | if is_pm { "PM" } else { "AM" } 26 | ); 27 | println!( 28 | "And there have been {} seconds since midnight", 29 | now.num_seconds_from_midnight() 30 | ); 31 | 32 | let (is_common_era, year) = now.year_ce(); 33 | println!( 34 | "The current UTC date is {}-{:02}-{:02} {:?} ({})", 35 | year, 36 | now.month(), 37 | now.day(), 38 | now.weekday(), 39 | if is_common_era { "CE" } else { "BCE" } 40 | ); 41 | println!( 42 | "And the Common Era began {} days ago", 43 | now.num_days_from_ce() 44 | ); 45 | } 46 | ``` 47 | 48 | [`Datelike`]: https://docs.rs/chrono/*/chrono/trait.Datelike.html 49 | [`DateTime`]: https://docs.rs/chrono/*/chrono/struct.DateTime.html 50 | [`Timelike`]: https://docs.rs/chrono/*/chrono/trait.Timelike.html 51 | -------------------------------------------------------------------------------- /src/text/regex/replace.md: -------------------------------------------------------------------------------- 1 | ## 文本模式替换 2 | 3 | 8 | 9 | [![regex-badge]][regex] [![lazy_static-badge]][lazy_static] [![cat-text-processing-badge]][cat-text-processing] 10 | 11 | 将所有出现的国际标准 ISO 8601 日期模式 *YYYY-MM-DD* 替换为具有斜杠的等效美式英语日期模式。例如: `2013-01-15` 替换为 `01/15/2013`。 12 | 13 | [`Regex::replace_all`] 方法将替换整个正则表示匹配的所有内容。`&str` 实现了 `Replacer` trait,它允许类似 `$abcde` 的变量引用相应的搜索匹配模式(search regex)中的命名捕获组 `(?PREGEX)`。有关示例和转义的详细信息,请参阅[替换字符串语法][replacement string syntax]。 14 | 15 | > 译者注:正则表达式的使用,需要了解匹配规则:全文匹配(match regex)、搜索匹配(search regex)、替换匹配(replace regex)。 16 | 17 | ```rust,edition2018 18 | use lazy_static::lazy_static; 19 | 20 | use std::borrow::Cow; 21 | use regex::Regex; 22 | 23 | fn reformat_dates(before: &str) -> Cow { 24 | lazy_static! { 25 | static ref ISO8601_DATE_REGEX : Regex = Regex::new( 26 | r"(?P\d{4})-(?P\d{2})-(?P\d{2})" 27 | ).unwrap(); 28 | } 29 | ISO8601_DATE_REGEX.replace_all(before, "$m/$d/$y") 30 | } 31 | 32 | fn main() { 33 | let before = "2012-03-14, 2013-01-15 and 2014-07-05"; 34 | let after = reformat_dates(before); 35 | assert_eq!(after, "03/14/2012, 01/15/2013 and 07/05/2014"); 36 | } 37 | ``` 38 | 39 | [`Regex::replace_all`]: https://docs.rs/regex/*/regex/struct.Regex.html#method.replace_all 40 | 41 | [replacement string syntax]: https://docs.rs/regex/*/regex/struct.Regex.html#replacement-string-syntax 42 | -------------------------------------------------------------------------------- /src/web/url/base.md: -------------------------------------------------------------------------------- 1 | ## 通过移除路径段创建基本 URL 2 | 3 | 8 | 9 | [![url-badge]][url] [![cat-net-badge]][cat-net] 10 | 11 | 基本 URL(base URL)包括协议和域名。但基本 URL(base URL)不包括目录、文件或查询字符串,这些项都可以从给定的 URL 中剥离出来。创建基本 URL(base URL)时,通过 [`PathSegmentsMut::clear`] 方法移除目录和文件路径,通过方法 [`Url::set_query`] 移除查询字符串。 12 | 13 | ```rust,edition2018 14 | # use error_chain::error_chain; 15 | 16 | use url::Url; 17 | # 18 | # error_chain! { 19 | # foreign_links { 20 | # UrlParse(url::ParseError); 21 | # } 22 | # errors { 23 | # CannotBeABase 24 | # } 25 | # } 26 | 27 | fn main() -> Result<()> { 28 | let full = "https://github.com/rust-lang/cargo?asdf"; 29 | 30 | let url = Url::parse(full)?; 31 | let base = base_url(url)?; 32 | 33 | assert_eq!(base.as_str(), "https://github.com/"); 34 | println!("The base of the URL is: {}", base); 35 | 36 | Ok(()) 37 | } 38 | 39 | fn base_url(mut url: Url) -> Result { 40 | match url.path_segments_mut() { 41 | Ok(mut path) => { 42 | path.clear(); 43 | } 44 | Err(_) => { 45 | return Err(Error::from_kind(ErrorKind::CannotBeABase)); 46 | } 47 | } 48 | 49 | url.set_query(None); 50 | 51 | Ok(url) 52 | } 53 | ``` 54 | 55 | [`PathSegmentsMut::clear`]: https://docs.rs/url/*/url/struct.PathSegmentsMut.html#method.clear 56 | [`Url::set_query`]: https://docs.rs/url/*/url/struct.Url.html#method.set_query 57 | -------------------------------------------------------------------------------- /src/development_tools/versioning/semver-complex.md: -------------------------------------------------------------------------------- 1 | ## 解析复杂的版本字符串 2 | 3 | 8 | 9 | [![semver-badge]][semver] [![cat-config-badge]][cat-config] 10 | 11 | 使用 [`Version::parse`] 从复杂的版本字符串构造语义化版本 [`semver::Version`]。该字符串包含[语义化版本控制规范][Semantic Versioning Specification]中定义的预发布和构建元数据。 12 | 13 | 需要注意的是:根据[语义化版本控制规范][Semantic Versioning Specification],构建元数据是虽然被解析,但在比较版本时不考虑。换句话说,即使两个版本的构建字符串不同,但它们的版本可能是相等的。 14 | 15 | ```rust,edition2018 16 | use semver::{Identifier, Version, SemVerError}; 17 | 18 | fn main() -> Result<(), SemVerError> { 19 | let version_str = "1.0.49-125+g72ee7853"; 20 | let parsed_version = Version::parse(version_str)?; 21 | 22 | assert_eq!( 23 | parsed_version, 24 | Version { 25 | major: 1, 26 | minor: 0, 27 | patch: 49, 28 | pre: vec![Identifier::Numeric(125)], 29 | build: vec![], 30 | } 31 | ); 32 | assert_eq!( 33 | parsed_version.build, 34 | vec![Identifier::AlphaNumeric(String::from("g72ee7853"))] 35 | ); 36 | 37 | let serialized_version = parsed_version.to_string(); 38 | assert_eq!(&serialized_version, version_str); 39 | 40 | Ok(()) 41 | } 42 | ``` 43 | 44 | [`semver::Version`]: https://docs.rs/semver/*/semver/struct.Version.html 45 | [`Version::parse`]: https://docs.rs/semver/*/semver/struct.Version.html#method.parse 46 | 47 | [Semantic Versioning Specification]: http://semver.org/ 48 | -------------------------------------------------------------------------------- /src/datetime.md: -------------------------------------------------------------------------------- 1 | # 日期及时间 2 | 3 | 8 | 9 | ## 期间和计算 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [测量运行时间][ex-measure-elapsed-time] | [![std-badge]][std] | [![cat-time-badge]][cat-time] | 14 | | [执行日期检查和时间计算][ex-datetime-arithmetic] | [![chrono-badge]][chrono] | [![cat-date-and-time-badge]][cat-date-and-time] | 15 | | [时间的时区转换][ex-convert-datetime-timezone] | [![chrono-badge]][chrono] | [![cat-date-and-time-badge]][cat-date-and-time] | 16 | 17 | ## 解析与显示 18 | 19 | | 实例名称 | Crates | 类别 | 20 | |--------|--------|------------| 21 | | [检查日期和时间][ex-examine-date-and-time] | [![chrono-badge]][chrono] | [![cat-date-and-time-badge]][cat-date-and-time] | 22 | | [日期和 UNIX 时间戳的互相转换][ex-convert-datetime-timestamp] | [![chrono-badge]][chrono] | [![cat-date-and-time-badge]][cat-date-and-time] | 23 | | [日期和时间的格式化显示][ex-format-datetime] | [![chrono-badge]][chrono] | [![cat-date-and-time-badge]][cat-date-and-time] | 24 | | [将字符串解析为 DateTime 结构体][ex-parse-datetime] | [![chrono-badge]][chrono] | [![cat-date-and-time-badge]][cat-date-and-time] | 25 | 26 | [ex-measure-elapsed-time]: datetime/duration.md#测量运行时间 27 | [ex-datetime-arithmetic]: datetime/duration.md#执行日期检查和时间计算 28 | [ex-convert-datetime-timezone]: datetime/duration.md#时间的时区转换 29 | 30 | [ex-examine-date-and-time]: datetime/parse.md#检查日期和时间 31 | [ex-convert-datetime-timestamp]: datetime/parse.md#日期和-unix-时间戳的互相转换 32 | [ex-format-datetime]: datetime/parse.md#日期和时间的格式化显示 33 | [ex-parse-datetime]: datetime/parse.md#将字符串解析为-datetime-结构体 34 | 35 | {{#include links.md}} 36 | -------------------------------------------------------------------------------- /src/datetime/parse/timestamp.md: -------------------------------------------------------------------------------- 1 | ## 日期和 UNIX 时间戳的互相转换 2 | 3 | 8 | 9 | [![chrono-badge]][chrono] [![cat-date-and-time-badge]][cat-date-and-time] 10 | 11 | 使用 [`NaiveDateTime::timestamp`] 将由 [`NaiveDate::from_ymd`] 生成的日期和由 [`NaiveTime::from_hms`] 生成的时间转换为 [UNIX 时间戳][UNIX timestamp]。然后,它使用 [`NaiveDateTime::from_timestamp`] 计算自 UTC 时间 1970 年 01 月 01 日 00:00:00 开始的 10 亿秒后的日期。 12 | 13 | ```rust,edition2018 14 | 15 | use chrono::{NaiveDate, NaiveDateTime}; 16 | 17 | fn main() { 18 | let date_time: NaiveDateTime = NaiveDate::from_ymd(2017, 11, 12).and_hms(17, 33, 44); 19 | println!( 20 | "Number of seconds between 1970-01-01 00:00:00 and {} is {}.", 21 | date_time, date_time.timestamp()); 22 | 23 | let date_time_after_a_billion_seconds = NaiveDateTime::from_timestamp(1_000_000_000, 0); 24 | println!( 25 | "Date after a billion seconds since 1970-01-01 00:00:00 was {}.", 26 | date_time_after_a_billion_seconds); 27 | } 28 | ``` 29 | 30 | [`NaiveDate::from_ymd`]: https://docs.rs/chrono/*/chrono/naive/struct.NaiveDate.html#method.from_ymd 31 | [`NaiveDateTime::from_timestamp`]: https://docs.rs/chrono/*/chrono/naive/struct.NaiveDateTime.html#method.from_timestamp 32 | [`NaiveDateTime::timestamp`]: https://docs.rs/chrono/*/chrono/naive/struct.NaiveDateTime.html#method.timestamp 33 | [`NaiveTime::from_hms`]: https://docs.rs/chrono/*/chrono/naive/struct.NaiveTime.html#method.from_hms 34 | 35 | [UNIX timestamp]: https://en.wikipedia.org/wiki/Unix_time 36 | -------------------------------------------------------------------------------- /src/development_tools/build_tools/cc-defines.md: -------------------------------------------------------------------------------- 1 | ## 编译 C 语言库时自定义设置 2 | 3 | 8 | 9 | [![cc-badge]][cc] [![cat-development-tools-badge]][cat-development-tools] 10 | 11 | 使用 [`cc::Build::define`] 自定义构建绑定的 C 语言代码非常简单。该方法接受 [`Option`] 值,因此可以创建这样的定义:`#define APP_NAME "foo"`、`#define WELCOME`(将 `None` 作为不确定值传递)。如下实例构建了一个绑定的 C 语言文件,其在 `build.rs` 中设置了动态定义,并在运行时打印 “**Welcome to foo - version 1.0.2**”。Cargo 设定了一些[环境变量][cargo-env],这些变量可能对某些自定义设置有用。 12 | 13 | ### `Cargo.toml` 14 | 15 | ```toml 16 | [package] 17 | ... 18 | version = "1.0.2" 19 | build = "build.rs" 20 | 21 | [build-dependencies] 22 | cc = "1" 23 | ``` 24 | 25 | ### `build.rs` 26 | 27 | ```rust,edition2018,no_run 28 | fn main() { 29 | cc::Build::new() 30 | .define("APP_NAME", "\"foo\"") 31 | .define("VERSION", format!("\"{}\"", env!("CARGO_PKG_VERSION")).as_str()) 32 | .define("WELCOME", None) 33 | .file("src/foo.c") 34 | .compile("foo"); 35 | } 36 | ``` 37 | 38 | ### `src/foo.c` 39 | 40 | ```c 41 | #include 42 | 43 | void print_app_info() { 44 | #ifdef WELCOME 45 | printf("Welcome to "); 46 | #endif 47 | printf("%s - version %s\n", APP_NAME, VERSION); 48 | } 49 | ``` 50 | 51 | ### `src/main.rs` 52 | 53 | ```rust,edition2018,ignore 54 | extern { 55 | fn print_app_info(); 56 | } 57 | 58 | fn main(){ 59 | unsafe { 60 | print_app_info(); 61 | } 62 | } 63 | ``` 64 | 65 | [cargo-env]: https://doc.rust-lang.org/cargo/reference/environment-variables.html 66 | -------------------------------------------------------------------------------- /src/encoding/string/percent-encode.md: -------------------------------------------------------------------------------- 1 | ## 百分比编码(URL 编码)字符串 2 | 3 | 8 | 9 | [![percent-encoding-badge]][percent-encoding] [![cat-encoding-badge]][cat-encoding] 10 | 11 | 使用 `percent-encoding` crate 中的 [`utf8_percent_encode`] 函数对输入字符串进行[百分比编码(URL 编码)][percent-encoding]。解码使用 [`percent_decode`] 函数。 12 | 13 | ```rust,edition2018 14 | use percent_encoding::{utf8_percent_encode, percent_decode, AsciiSet, CONTROLS}; 15 | use std::str::Utf8Error; 16 | 17 | /// https://url.spec.whatwg.org/#fragment-percent-encode-set 18 | const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`'); 19 | 20 | fn main() -> Result<(), Utf8Error> { 21 | let input = "confident, productive systems programming"; 22 | 23 | let iter = utf8_percent_encode(input, FRAGMENT); 24 | let encoded: String = iter.collect(); 25 | assert_eq!(encoded, "confident,%20productive%20systems%20programming"); 26 | 27 | let iter = percent_decode(encoded.as_bytes()); 28 | let decoded = iter.decode_utf8()?; 29 | assert_eq!(decoded, "confident, productive systems programming"); 30 | 31 | Ok(()) 32 | } 33 | ``` 34 | 35 | 编码集定义哪些字节(除了非 ASCII 字节和控制键之外)需要进行百分比编码(URL 编码),这个集合的选择取决于上下文。例如,`url` 对 URL 路径中的 `?` 编码,而不对查询字符串中的 `?` 编码。 36 | 37 | 编码的返回值是 `&str` 切片的迭代器,然后聚集为一个字符串 `String`。 38 | 39 | [`percent_decode`]: https://docs.rs/percent-encoding/*/percent_encoding/fn.percent_decode.html 40 | [`utf8_percent_encode`]: https://docs.rs/percent-encoding/*/percent_encoding/fn.utf8_percent_encode.html 41 | 42 | [percent-encoding]: https://en.wikipedia.org/wiki/Percent-encoding 43 | -------------------------------------------------------------------------------- /src/development_tools/versioning/semver-increment.md: -------------------------------------------------------------------------------- 1 | ## 解析并递增版本字符串 2 | 3 | 8 | 9 | [![semver-badge]][semver] [![cat-config-badge]][cat-config] 10 | 11 | 使用 [`Version::parse`] 从字符串字面量构造语义化版本 [`semver::Version`],然后逐个递增补丁(修订)版本号、副(次要)版本号和主版本号。 12 | 13 | 注意:根据[语义化版本控制规范][Semantic Versioning Specification],增加副(次要)版本号时会将补丁(修订)版本号重置为 0,增加主版本号时会将副(次要)版本号和补丁(修订)版本号都重置为 0。 14 | 15 | ```rust,edition2018 16 | use semver::{Version, SemVerError}; 17 | 18 | fn main() -> Result<(), SemVerError> { 19 | let mut parsed_version = Version::parse("0.2.6")?; 20 | 21 | assert_eq!( 22 | parsed_version, 23 | Version { 24 | major: 0, 25 | minor: 2, 26 | patch: 6, 27 | pre: vec![], 28 | build: vec![], 29 | } 30 | ); 31 | 32 | parsed_version.increment_patch(); 33 | assert_eq!(parsed_version.to_string(), "0.2.7"); 34 | println!("New patch release: v{}", parsed_version); 35 | 36 | parsed_version.increment_minor(); 37 | assert_eq!(parsed_version.to_string(), "0.3.0"); 38 | println!("New minor release: v{}", parsed_version); 39 | 40 | parsed_version.increment_major(); 41 | assert_eq!(parsed_version.to_string(), "1.0.0"); 42 | println!("New major release: v{}", parsed_version); 43 | 44 | Ok(()) 45 | } 46 | ``` 47 | 48 | [`semver::Version`]: https://docs.rs/semver/*/semver/struct.Version.html 49 | [`Version::parse`]: https://docs.rs/semver/*/semver/struct.Version.html#method.parse 50 | 51 | [Semantic Versioning Specification]: http://semver.org/ 52 | -------------------------------------------------------------------------------- /src/web/url/origin.md: -------------------------------------------------------------------------------- 1 | ## 提取 URL 源(scheme / host / port) 2 | 3 | 8 | 9 | [![url-badge]][url] [![cat-net-badge]][cat-net] 10 | 11 | [`Url`] 结构体定义了多种方法,以便于提取有关它所表示的 URL 的信息。 12 | 13 | ```rust,edition2018 14 | 15 | use url::{Url, Host, ParseError}; 16 | 17 | fn main() -> Result<(), ParseError> { 18 | let s = "ftp://rust-lang.org/examples"; 19 | 20 | let url = Url::parse(s)?; 21 | 22 | assert_eq!(url.scheme(), "ftp"); 23 | assert_eq!(url.host(), Some(Host::Domain("rust-lang.org"))); 24 | assert_eq!(url.port_or_known_default(), Some(21)); 25 | println!("The origin is as expected!"); 26 | 27 | Ok(()) 28 | } 29 | ``` 30 | 31 | [`origin`] 方法产生相同的结果。 32 | 33 | ```rust,edition2018 34 | # use error_chain::error_chain; 35 | 36 | use url::{Url, Origin, Host}; 37 | 38 | # error_chain! { 39 | # foreign_links { 40 | # UrlParse(url::ParseError); 41 | # } 42 | # } 43 | # 44 | fn main() -> Result<()> { 45 | let s = "ftp://rust-lang.org/examples"; 46 | 47 | let url = Url::parse(s)?; 48 | 49 | let expected_scheme = "ftp".to_owned(); 50 | let expected_host = Host::Domain("rust-lang.org".to_owned()); 51 | let expected_port = 21; 52 | let expected = Origin::Tuple(expected_scheme, expected_host, expected_port); 53 | 54 | let origin = url.origin(); 55 | assert_eq!(origin, expected); 56 | println!("The origin is as expected!"); 57 | 58 | Ok(()) 59 | } 60 | ``` 61 | 62 | [`origin`]: https://docs.rs/url/*/url/struct.Url.html#method.origin 63 | [`Url`]: https://docs.rs/url/*/url/struct.Url.html 64 | -------------------------------------------------------------------------------- /src/development_tools/debugging/config_log/log-mod.md: -------------------------------------------------------------------------------- 1 | ## 启用每个模块的日志级别 2 | 3 | 8 | 9 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging] 10 | 11 | 创建两个模块:`foo` 和其嵌套的 `foo::bar`,日志记录指令分别由 [`RUST_LOG`] 环境变量控制。 12 | 13 | ```rust,edition2018 14 | 15 | mod foo { 16 | mod bar { 17 | pub fn run() { 18 | log::warn!("[bar] warn"); 19 | log::info!("[bar] info"); 20 | log::debug!("[bar] debug"); 21 | } 22 | } 23 | 24 | pub fn run() { 25 | log::warn!("[foo] warn"); 26 | log::info!("[foo] info"); 27 | log::debug!("[foo] debug"); 28 | bar::run(); 29 | } 30 | } 31 | 32 | fn main() { 33 | env_logger::init(); 34 | log::warn!("[root] warn"); 35 | log::info!("[root] info"); 36 | log::debug!("[root] debug"); 37 | foo::run(); 38 | } 39 | ``` 40 | 41 | [`RUST_LOG`] 环境变量控制 [`env_logger`][env_logger] 的输出。模块声明采用逗号分隔各项,格式类似于 `path::to::module=log_level`。按如下方式运行 `test` 应用程序: 42 | 43 | ```bash 44 | RUST_LOG="warn,test::foo=info,test::foo::bar=debug" ./test 45 | ``` 46 | 47 | 将日志等级 [`log::Level`] 的默认值设置为 `warn`,将模块 `foo` 和其嵌套的模块 `foo::bar` 的日志等级设置为 `info` 和 `debug`。 48 | 49 | ```bash 50 | WARN:test: [root] warn 51 | WARN:test::foo: [foo] warn 52 | INFO:test::foo: [foo] info 53 | WARN:test::foo::bar: [bar] warn 54 | INFO:test::foo::bar: [bar] info 55 | DEBUG:test::foo::bar: [bar] debug 56 | ``` 57 | 58 | [`log::Level`]: https://docs.rs/log/*/log/enum.Level.html 59 | [`RUST_LOG`]: https://docs.rs/env_logger/*/env_logger/#enabling-logging 60 | -------------------------------------------------------------------------------- /src/text.md: -------------------------------------------------------------------------------- 1 | # 文本处理 2 | 3 | 8 | 9 | ## 正则表达式 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [验证并提取电子邮件登录信息][ex-verify-extract-email] | [![regex-badge]][regex] [![lazy_static-badge]][lazy_static] | [![cat-text-processing-badge]][cat-text-processing] | 14 | | [从文本提取标签元素唯一的列表][ex-extract-hashtags] | [![regex-badge]][regex] [![lazy_static-badge]][lazy_static] | [![cat-text-processing-badge]][cat-text-processing] | 15 | | [从文本提取电话号码][ex-phone] | [![regex-badge]][regex] | [![cat-text-processing-badge]][cat-text-processing] | 16 | | [通过匹配多个正则表达式来筛选日志文件][ex-regex-filter-log] | [![regex-badge]][regex] | [![cat-text-processing-badge]][cat-text-processing] 17 | | [文本模式替换][ex-regex-replace-named] | [![regex-badge]][regex] [![lazy_static-badge]][lazy_static] | [![cat-text-processing-badge]][cat-text-processing] | 18 | 19 | ## 字符串解析 20 | 21 | | 实例名称 | Crates | 类别 | 22 | |--------|--------|------------| 23 | | [收集 Unicode 字符][ex-unicode-graphemes] | [![unicode-segmentation-badge]][unicode-segmentation] | [![cat-encoding-badge]][cat-text-processing] | 24 | | [自定义`结构体`并实现 `FromStr` trait][string_parsing-from_str] | [![std-badge]][std] | [![cat-text-processing-badge]][cat-text-processing] | 25 | 26 | [ex-verify-extract-email]: text/regex.md#验证并提取电子邮件登录信息 27 | [ex-extract-hashtags]: text/regex.md#从文本提取标签元素唯一的列表 28 | [ex-phone]: text/regex.md#从文本提取电话号码 29 | [ex-regex-filter-log]: text/regex.md#通过匹配多个正则表达式来筛选日志文件 30 | [ex-regex-replace-named]: text/regex.md#文本模式替换 31 | 32 | [ex-unicode-graphemes]: text/string_parsing.md#收集-unicode-字符 33 | [string_parsing-from_str]: text/string_parsing.md#自定义结构体并实现-fromstr-trait 34 | 35 | {{#include links.md}} 36 | -------------------------------------------------------------------------------- /src/text/string_parsing/from_str.md: -------------------------------------------------------------------------------- 1 | ## 自定义`结构体`并实现 `FromStr` trait 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-text-processing-badge]][cat-text-processing] 10 | 11 | 本实例中,创建一个自定义结构体 `RGB` 并实现 `FromStr` trait,以将提供的颜色十六进制代码转换为其 RGB 颜色代码。 12 | 13 | ```rust,edition2018 14 | use std::str::FromStr; 15 | 16 | #[derive(Debug, PartialEq)] 17 | struct RGB { 18 | r: u8, 19 | g: u8, 20 | b: u8, 21 | } 22 | 23 | impl FromStr for RGB { 24 | type Err = std::num::ParseIntError; 25 | 26 | // 解析格式为 '#rRgGbB..' 的颜色十六进制代码 27 | // 将其转换为 'RGB' 实例 28 | fn from_str(hex_code: &str) -> Result { 29 | 30 | // u8::from_str_radix(src: &str, radix: u32) 31 | // 将给定的字符串切片转换为 u8 32 | let r: u8 = u8::from_str_radix(&hex_code[1..3], 16)?; 33 | let g: u8 = u8::from_str_radix(&hex_code[3..5], 16)?; 34 | let b: u8 = u8::from_str_radix(&hex_code[5..7], 16)?; 35 | 36 | Ok(RGB { r, g, b }) 37 | } 38 | } 39 | 40 | fn main() { 41 | let code: &str = &r"#fa7268"; 42 | match RGB::from_str(code) { 43 | Ok(rgb) => { 44 | println!( 45 | r"The RGB color code is: R: {} G: {} B: {}", 46 | rgb.r, rgb.g, rgb.b 47 | ); 48 | } 49 | Err(_) => { 50 | println!("{} is not a valid color hex code!", code); 51 | } 52 | } 53 | 54 | // 测试 from_str 函数执行是否符合预期 55 | assert_eq!( 56 | RGB::from_str(&r"#fa7268").unwrap(), 57 | RGB { 58 | r: 250, 59 | g: 114, 60 | b: 104 61 | } 62 | ); 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /src/text/regex/filter-log.md: -------------------------------------------------------------------------------- 1 | ## 通过匹配多个正则表达式来筛选日志文件 2 | 3 | 8 | 9 | [![regex-badge]][regex] [![cat-text-processing-badge]][cat-text-processing] 10 | 11 | 读取名为 `application.log` 的文件,并且只输出包含下列内容的行:“version X.X.X”、端口为 443 的 IP 地址(如 “192.168.0.1:443”)、特定警告。 12 | 13 | 正则表达集构造器 [`regex::RegexSetBuilder`] 构建了正则表达式集 [`regex::RegexSet`]。由于反斜杠在正则表达式中非常常见,因此使用[原始字符串字面量][raw string literals]可以使它们更具可读性。 14 | 15 | ```rust,edition2018,no_run 16 | # use error_chain::error_chain; 17 | 18 | use std::fs::File; 19 | use std::io::{BufReader, BufRead}; 20 | use regex::RegexSetBuilder; 21 | 22 | # error_chain! { 23 | # foreign_links { 24 | # Io(std::io::Error); 25 | # Regex(regex::Error); 26 | # } 27 | # } 28 | # 29 | fn main() -> Result<()> { 30 | let log_path = "application.log"; 31 | let buffered = BufReader::new(File::open(log_path)?); 32 | 33 | let set = RegexSetBuilder::new(&[ 34 | r#"version "\d\.\d\.\d""#, 35 | r#"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:443"#, 36 | r#"warning.*timeout expired"#, 37 | ]).case_insensitive(true) 38 | .build()?; 39 | 40 | buffered 41 | .lines() 42 | .filter_map(|line| line.ok()) 43 | .filter(|line| set.is_match(line.as_str())) 44 | .for_each(|x| println!("{}", x)); 45 | 46 | Ok(()) 47 | } 48 | ``` 49 | 50 | [`regex::RegexSet`]: https://docs.rs/regex/*/regex/struct.RegexSet.html 51 | [`regex::RegexSetBuilder`]: https://docs.rs/regex/*/regex/struct.RegexSetBuilder.html 52 | 53 | [raw string literals]: https://rust-reference.budshome.com/tokens.html#%E5%AD%97%E9%9D%A2%E9%87%8F 54 | -------------------------------------------------------------------------------- /src/algorithms.md: -------------------------------------------------------------------------------- 1 | # 算法 2 | 3 | 8 | 9 | ## 生成随机值 10 | 11 | | 实例名称 | Crates | 类别 | 12 | |--------|--------|------------| 13 | | [生成随机数][ex-rand] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | 14 | | [生成范围内随机数][ex-rand-range] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | 15 | | [生成给定分布随机数][ex-rand-dist] | [![rand-badge]][rand] [![rand_distr-badge]][rand_distr] | [![cat-science-badge]][cat-science] | 16 | | [生成自定义类型随机值][ex-rand-custom] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | 17 | | [从一组字母数字字符创建随机密码][ex-rand-passwd] | [![rand-badge]][rand] | [![cat-os-badge]][cat-os] | 18 | | [从一组用户定义字符创建随机密码][ex-rand-choose] | [![rand-badge]][rand] | [![cat-os-badge]][cat-os] | 19 | 20 | ## Vector 排序 21 | 22 | | 实例名称 | Crates | 类别 | 23 | |--------|--------|------------| 24 | | [整数 Vector 排序][ex-sort-integers] | [![std-badge]][std] | [![cat-science-badge]][cat-science] | 25 | | [浮点数 Vector 排序][ex-sort-floats] | [![std-badge]][std] | [![cat-science-badge]][cat-science] | 26 | | [结构体 Vector 排序][ex-sort-structs] | [![std-badge]][std] | [![cat-science-badge]][cat-science] | 27 | 28 | [ex-rand]: algorithms/randomness.md#生成随机数 29 | [ex-rand-range]: algorithms/randomness.md#生成范围内随机数 30 | [ex-rand-dist]: algorithms/randomness.md#生成给定分布随机数 31 | [ex-rand-custom]: algorithms/randomness.md#生成自定义类型随机值 32 | [ex-rand-passwd]: algorithms/randomness.md#从一组字母数字字符创建随机密码 33 | [ex-rand-choose]: algorithms/randomness.md#从一组用户定义字符创建随机密码 34 | 35 | [ex-sort-integers]: algorithms/sorting.md#整数-vector-排序 36 | [ex-sort-floats]: algorithms/sorting.md#浮点数-vector-排序 37 | [ex-sort-structs]: algorithms/sorting.md#结构体-vector-排序 38 | 39 | {{#include links.md}} 40 | -------------------------------------------------------------------------------- /src/web/clients/api/rest-get.md: -------------------------------------------------------------------------------- 1 | ## 查询 GitHub API 2 | 3 | 8 | 9 | [![reqwest-badge]][reqwest] [![serde-badge]][serde] [![cat-net-badge]][cat-net] [![cat-encoding-badge]][cat-encoding] 10 | 11 | 使用 [`reqwest::get`] 查询 [点赞的用户 API v3](https://docs.github.com/cn/free-pro-team@latest/rest/reference/activity#list-stargazers),以获取某个 GitHub 项目的所有点赞用户的列表。使用 [`Response::json`] 将响应信息 [`reqwest::Response`] 反序列化为实现了 [`serde::Deserialize`] trait 的 `User` 对象。 12 | 13 | [tokio::main] 用于设置异步执行器,该进程异步等待 [`reqwest::get`] 完成,然后将响应信息反序列化到用户实例中。 14 | 15 | ```rust,edition2018,no_run 16 | use serde::Deserialize; 17 | use reqwest::Error; 18 | 19 | #[derive(Deserialize, Debug)] 20 | struct User { 21 | login: String, 22 | id: u32, 23 | } 24 | 25 | #[tokio::main] 26 | async fn main() -> Result<(), Error> { 27 | let request_url = format!("https://api.github.com/repos/{owner}/{repo}/stargazers", 28 | owner = "rust-lang-nursery", 29 | repo = "rust-cookbook"); 30 | println!("{}", request_url); 31 | let response = reqwest::get(&request_url).await?; 32 | 33 | let users: Vec = response.json().await?; 34 | println!("{:?}", users); 35 | Ok(()) 36 | } 37 | ``` 38 | 39 | [`reqwest::get`]: https://docs.rs/reqwest/*/reqwest/fn.get.html 40 | [`reqwest::Response`]: https://docs.rs/reqwest/*/reqwest/struct.Response.html 41 | [`Response::json`]: https://docs.rs/reqwest/*/reqwest/struct.Response.html#method.json 42 | [`serde::Deserialize`]: https://docs.rs/serde/*/serde/trait.Deserialize.html 43 | [tokio::main]: https://docs.rs/tokio/0.2.22/tokio/attr.main.html -------------------------------------------------------------------------------- /src/compression/tar/tar-strip-prefix.md: -------------------------------------------------------------------------------- 1 | ## 从路径移除前缀时,解压 tar 包 2 | 3 | 8 | 9 | [![flate2-badge]][flate2] [![tar-badge]][tar] [![cat-compression-badge]][cat-compression] 10 | 11 | 循环遍历 [`Archive::entries`]。使用 [`Path::strip_prefix`] 移除指定的路径前缀(`bundle/logs`)。最终,通过 [`Entry::unpack`] 提取 [`tar::Entry`](tar 包中的内容)。 12 | 13 | ```rust,edition2018,no_run 14 | # use error_chain::error_chain; 15 | use std::fs::File; 16 | use std::path::PathBuf; 17 | use flate2::read::GzDecoder; 18 | use tar::Archive; 19 | # 20 | # error_chain! { 21 | # foreign_links { 22 | # Io(std::io::Error); 23 | # StripPrefixError(::std::path::StripPrefixError); 24 | # } 25 | # } 26 | 27 | fn main() -> Result<()> { 28 | let file = File::open("archive.tar.gz")?; 29 | let mut archive = Archive::new(GzDecoder::new(file)); 30 | let prefix = "bundle/logs"; 31 | 32 | println!("Extracted the following files:"); 33 | archive 34 | .entries()? 35 | .filter_map(|e| e.ok()) 36 | .map(|mut entry| -> Result { 37 | let path = entry.path()?.strip_prefix(prefix)?.to_owned(); 38 | entry.unpack(&path)?; 39 | Ok(path) 40 | }) 41 | .filter_map(|e| e.ok()) 42 | .for_each(|x| println!("> {}", x.display())); 43 | 44 | Ok(()) 45 | } 46 | ``` 47 | 48 | [`Archive::entries`]: https://docs.rs/tar/*/tar/struct.Archive.html#method.entries 49 | [`Entry::unpack`]: https://docs.rs/tar/*/tar/struct.Entry.html#method.unpack 50 | [`Path::strip_prefix`]: https://doc.rust-lang.org/std/path/struct.Path.html#method.strip_prefix 51 | [`tar::Entry`]: https://docs.rs/tar/*/tar/struct.Entry.html 52 | -------------------------------------------------------------------------------- /src/cryptography/hashing/sha-digest.md: -------------------------------------------------------------------------------- 1 | ## 计算文件的 SHA-256 摘要 2 | 3 | 8 | 9 | [![ring-badge]][ring] [![data-encoding-badge]][data-encoding] [![cat-cryptography-badge]][cat-cryptography] 10 | 11 | 如下实例中,先创建文件,写入一些数据。然后使用 [`digest::Context`] 计算文件内容的 SHA-256 摘要 [`digest::Digest`]。 12 | 13 | ```rust,edition2018 14 | # use error_chain::error_chain; 15 | use data_encoding::HEXUPPER; 16 | use ring::digest::{Context, Digest, SHA256}; 17 | use std::fs::File; 18 | use std::io::{BufReader, Read, Write}; 19 | # 20 | # error_chain! { 21 | # foreign_links { 22 | # Io(std::io::Error); 23 | # Decode(data_encoding::DecodeError); 24 | # } 25 | # } 26 | 27 | fn sha256_digest(mut reader: R) -> Result { 28 | let mut context = Context::new(&SHA256); 29 | let mut buffer = [0; 1024]; 30 | 31 | loop { 32 | let count = reader.read(&mut buffer)?; 33 | if count == 0 { 34 | break; 35 | } 36 | context.update(&buffer[..count]); 37 | } 38 | 39 | Ok(context.finish()) 40 | } 41 | 42 | fn main() -> Result<()> { 43 | let path = "file.txt"; 44 | 45 | let mut output = File::create(path)?; 46 | write!(output, "We will generate a digest of this text")?; 47 | 48 | let input = File::open(path)?; 49 | let reader = BufReader::new(input); 50 | let digest = sha256_digest(reader)?; 51 | 52 | println!("SHA-256 digest is {}", HEXUPPER.encode(digest.as_ref())); 53 | 54 | Ok(()) 55 | } 56 | ``` 57 | 58 | [`digest::Context`]: https://briansmith.org/rustdoc/ring/digest/struct.Context.html 59 | [`digest::Digest`]: https://briansmith.org/rustdoc/ring/digest/struct.Digest.html 60 | -------------------------------------------------------------------------------- /src/database/sqlite/transactions.md: -------------------------------------------------------------------------------- 1 | ## 事务处理 2 | 3 | 8 | 9 | [![rusqlite-badge]][rusqlite] [![cat-database-badge]][cat-database] 10 | 11 | [`Connection::open`] 将打开来自前述实例的数据库 `cats.db`。 12 | 13 | 使用 [`Connection::transaction`] 开始事务,除非使用 [`Transaction::commit`] 显式提交,否则事务将回滚。 14 | 15 | 在下面的实例中,颜色表对颜色名称具有唯一性约束。当尝试插入重复的颜色时,事务会回滚。 16 | 17 | ```rust,edition2018,no_run 18 | use rusqlite::{Connection, Result, NO_PARAMS}; 19 | 20 | fn main() -> Result<()> { 21 | let mut conn = Connection::open("cats.db")?; 22 | 23 | successful_tx(&mut conn)?; 24 | 25 | let res = rolled_back_tx(&mut conn); 26 | assert!(res.is_err()); 27 | 28 | Ok(()) 29 | } 30 | 31 | fn successful_tx(conn: &mut Connection) -> Result<()> { 32 | let tx = conn.transaction()?; 33 | 34 | tx.execute("delete from cat_colors", NO_PARAMS)?; 35 | tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?; 36 | tx.execute("insert into cat_colors (name) values (?1)", &[&"blue"])?; 37 | 38 | tx.commit() 39 | } 40 | 41 | fn rolled_back_tx(conn: &mut Connection) -> Result<()> { 42 | let tx = conn.transaction()?; 43 | 44 | tx.execute("delete from cat_colors", NO_PARAMS)?; 45 | tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?; 46 | tx.execute("insert into cat_colors (name) values (?1)", &[&"blue"])?; 47 | tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?; 48 | 49 | tx.commit() 50 | } 51 | ``` 52 | 53 | [`Connection::transaction`]: https://docs.rs/rusqlite/*/rusqlite/struct.Connection.html#method.transaction 54 | [`Transaction::commit`]: https://docs.rs/rusqlite/*/rusqlite/struct.Transaction.html#method.commit 55 | -------------------------------------------------------------------------------- /src/web/scraping/extract-links.md: -------------------------------------------------------------------------------- 1 | ## 从 HTML 网页中提取所有链接 2 | 3 | 8 | 9 | [![reqwest-badge]][reqwest] [![select-badge]][select] [![cat-net-badge]][cat-net] 10 | 11 | 使用 [`reqwest::get`] 执行 HTTP GET 请求,然后使用 [`Document::from_read`] 将响应信息解析为 HTML 文档。以“a”(锚元素)作为结构体 [`Name`] 的参数,将结构体 [`Name`] 作为条件,使用 [`find`] 方法检索所有链接。在结构体 [`Selection`] 上调用 [`filter_map`] 方法,从具有 “href” [`attr`](属性)的链接检索所有 URL。 12 | 13 | ```rust,edition2018,no_run 14 | use error_chain::error_chain; 15 | use select::document::Document; 16 | use select::predicate::Name; 17 | 18 | error_chain! { 19 | foreign_links { 20 | ReqError(reqwest::Error); 21 | IoError(std::io::Error); 22 | } 23 | } 24 | 25 | #[tokio::main] 26 | async fn main() -> Result<()> { 27 | let res = reqwest::get("https://www.rust-lang.org/en-US/") 28 | .await? 29 | .text() 30 | .await?; 31 | 32 | Document::from(res.as_str()) 33 | .find(Name("a")) 34 | .filter_map(|n| n.attr("href")) 35 | .for_each(|x| println!("{}", x)); 36 | 37 | Ok(()) 38 | } 39 | 40 | ``` 41 | 42 | [`attr`]: https://docs.rs/select/*/select/node/struct.Node.html#method.attr 43 | [`Document::from_read`]: https://docs.rs/select/*/select/document/struct.Document.html#method.from_read 44 | [`filter_map`]: https://doc.rust-lang.org/core/iter/trait.Iterator.html#method.filter_map 45 | [`find`]: https://docs.rs/select/*/select/document/struct.Document.html#method.find 46 | [`Name`]: https://docs.rs/select/*/select/predicate/struct.Name.html 47 | [`reqwest::get`]: https://docs.rs/reqwest/*/reqwest/fn.get.html 48 | [`Selection`]: https://docs.rs/select/*/select/selection/struct.Selection.html 49 | -------------------------------------------------------------------------------- /src/os/external/send-input.md: -------------------------------------------------------------------------------- 1 | ## 运行传递 stdin 的外部命令,并检查错误代码 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-os-badge]][cat-os] 10 | 11 | 使用外部命令 [`Command`] 打开 `python` 解释器,并传递一条 python 语句供其执行,然后解析语句的输出结构体 [`Output`]。 12 | 13 | ```rust,edition2018,no_run 14 | # use error_chain::error_chain; 15 | # 16 | use std::collections::HashSet; 17 | use std::io::Write; 18 | use std::process::{Command, Stdio}; 19 | # 20 | # error_chain!{ 21 | # errors { CmdError } 22 | # foreign_links { 23 | # Io(std::io::Error); 24 | # Utf8(std::string::FromUtf8Error); 25 | # } 26 | # } 27 | 28 | fn main() -> Result<()> { 29 | let mut child = Command::new("python").stdin(Stdio::piped()) 30 | .stderr(Stdio::piped()) 31 | .stdout(Stdio::piped()) 32 | .spawn()?; 33 | 34 | child.stdin 35 | .as_mut() 36 | .ok_or("Child process stdin has not been captured!")? 37 | .write_all(b"import this; copyright(); credits(); exit()")?; 38 | 39 | let output = child.wait_with_output()?; 40 | 41 | if output.status.success() { 42 | let raw_output = String::from_utf8(output.stdout)?; 43 | let words = raw_output.split_whitespace() 44 | .map(|s| s.to_lowercase()) 45 | .collect::>(); 46 | println!("Found {} unique words:", words.len()); 47 | println!("{:#?}", words); 48 | Ok(()) 49 | } else { 50 | let err = String::from_utf8(output.stderr)?; 51 | error_chain::bail!("External command failed:\n {}", err) 52 | } 53 | } 54 | ``` 55 | 56 | [`Command`]: https://doc.rust-lang.org/std/process/struct.Command.html 57 | [`Output`]: https://doc.rust-lang.org/std/process/struct.Output.html 58 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust-cookbook-zh-cn" 3 | version = "1.0.0" 4 | authors = ["Zhang Zhongyu ", "Brian Anderson ", "Andrew Gauger "] 5 | edition = "2018" 6 | license = "MIT/Apache-2.0" 7 | publish = false 8 | build = "build.rs" 9 | 10 | [dependencies] 11 | ansi_term = "0.11.0" 12 | approx = "0.3" 13 | base64 = "0.9" 14 | bitflags = "1.0" 15 | byteorder = "1.0" 16 | cc = "1.0" 17 | chrono = "0.4" 18 | clap = "2.29" 19 | crossbeam = "0.5" 20 | crossbeam-channel = "0.3.9" 21 | csv = "1.0" 22 | data-encoding = "2.1.0" 23 | env_logger = "0.5" 24 | error-chain = "0.12" 25 | flate2 = "1.0" 26 | glob = "0.3" 27 | image = "0.20" 28 | lazy_static = "1.0" 29 | log = "0.4" 30 | log4rs = "0.8" 31 | memmap = "0.7" 32 | mime = "0.3" 33 | nalgebra = { version = "0.16.12", features = ["serde-serialize"] } 34 | ndarray = { version = "0.13", features = ["approx"] } 35 | num = "0.2" 36 | num_cpus = "1.8" 37 | percent-encoding = "2.1" 38 | petgraph = "0.4" 39 | postgres = "0.17.2" 40 | rand = "0.7.3" 41 | rand_distr = "0.2.2" 42 | rayon = "1.0" 43 | regex = "1.0" 44 | reqwest = { version = "0.10", features = ["blocking", "json", "stream"] } 45 | ring = "0.16.11" 46 | rusqlite = { version = "0.22", features = ["chrono"] } 47 | same-file = "1.0" 48 | select = "0.4" 49 | semver = "0.9" 50 | serde = { version = "1.0", features = ["derive"] } 51 | serde_derive = "1.0" 52 | serde_json = "1.0" 53 | tar = "0.4.12" 54 | tempfile = "3.1" 55 | threadpool = "1.6" 56 | toml = "0.4" 57 | tokio = { version = "0.2", features = ["full"] } 58 | unicode-segmentation = "1.2.1" 59 | url = "2.1" 60 | walkdir = "2.0" 61 | 62 | [target.'cfg(target_os = "linux")'.dependencies] 63 | syslog = "5.0" 64 | 65 | [build-dependencies] 66 | skeptic = { git = 'https://github.com/andygauge/rust-skeptic'} 67 | walkdir = "2.0" 68 | 69 | [dev-dependencies] 70 | skeptic = { git = 'https://github.com/andygauge/rust-skeptic'} 71 | walkdir = "2.0" 72 | -------------------------------------------------------------------------------- /src/errors/handle/main.md: -------------------------------------------------------------------------------- 1 | ## 在 main 方法中对错误适当处理 2 | 3 | 8 | 9 | [![error-chain-badge]][error-chain] [![cat-rust-patterns-badge]][cat-rust-patterns] 10 | 11 | 处理尝试打开不存在的文件时发生的错误,是通过使用 [error-chain] crate 来实现的。[error-chain] crate 包含大量的模板代码,用于 [Rust 中的错误处理]。 12 | 13 | [`foreign_links`] 代码块内的 `Io(std::io::Error)` 函数允许由 [`std::io::Error`] 所报错误信息到 [`error_chain!`] 所定义错误类型的自动转换,[`error_chain!`] 所定义错误类型将实现 [`Error`] trait。 14 | 15 | 下文的实例将通过打开 Unix 文件 `/proc/uptime` 并解析内容以获得其中第一个数字,从而告诉系统运行了多长时间。除非出现错误,否则返回正常运行时间。 16 | 17 | 本书中的其他实例将隐藏 [error-chain] 模板,如果需要查看,可以通过 ⤢ 按钮展开代码。 18 | 19 | ```rust,edition2018 20 | use error_chain::error_chain; 21 | 22 | use std::fs::File; 23 | use std::io::Read; 24 | 25 | error_chain!{ 26 | foreign_links { 27 | Io(std::io::Error); 28 | ParseInt(::std::num::ParseIntError); 29 | } 30 | } 31 | 32 | fn read_uptime() -> Result { 33 | let mut uptime = String::new(); 34 | File::open("/proc/uptime")?.read_to_string(&mut uptime)?; 35 | 36 | Ok(uptime 37 | .split('.') 38 | .next() 39 | .ok_or("Cannot parse uptime data")? 40 | .parse()?) 41 | } 42 | 43 | fn main() { 44 | match read_uptime() { 45 | Ok(uptime) => println!("uptime: {} seconds", uptime), 46 | Err(err) => eprintln!("error: {}", err), 47 | }; 48 | } 49 | ``` 50 | 51 | [`error_chain!`]: https://docs.rs/error-chain/*/error_chain/macro.error_chain.html 52 | [`Error`]: https://doc.rust-lang.org/std/error/trait.Error.html 53 | [`foreign_links`]: https://docs.rs/error-chain/*/error_chain/#foreign-links 54 | [`std::io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html 55 | 56 | [Rust 中的错误处理]: https://rust-lang.budshome.com/ch09-00-error-handling.html 57 | -------------------------------------------------------------------------------- /src/science/mathematics/linear_algebra/vector-comparison.md: -------------------------------------------------------------------------------- 1 | ## Vector 比较 2 | 3 | 8 | 9 | [![ndarray-badge]][ndarray] 10 | 11 | [ndarray] crate 支持多种创建数组的方法——此实例使用 `from` 从 `std::Vec` 创建数组 [`ndarray::Array`]。然后,对数组以元素方式求和。 12 | 13 | 下面的实例按元素方式比较两个浮点型 vector。浮点数的存储通常不精确,因此很难进行精确的比较。但是,[`approx`] crate 中的 [`assert_abs_diff_eq!`] 宏允许方便地比较浮点型元素。要将 `approx` 和 `ndarray` 两个 crate一起使用,必须在 `Cargo.toml` 文件中的 `ndarray` 依赖项添加 `approx` 特性。例如:`ndarray = { version = "0.13", features = ["approx"] }`。 14 | 15 | 此实例还包含其他所有权示例。在这里,`let z = a + b` 执行后,会销毁 `a` and `b`,然后所有权会转移到 `z`。或者,`let w = &c + &d` 创建一个新的 vector,而不销毁 `c` 或者 `d`,允许以后对它们进行修改。有关其他详细信息,请参见[带有两个数组的二进制运算符][Binary Operators With Two Arrays]。 16 | 17 | ```rust,edition2018 18 | use approx::assert_abs_diff_eq; 19 | use ndarray::Array; 20 | 21 | fn main() { 22 | let a = Array::from(vec![1., 2., 3., 4., 5.]); 23 | let b = Array::from(vec![5., 4., 3., 2., 1.]); 24 | let mut c = Array::from(vec![1., 2., 3., 4., 5.]); 25 | let mut d = Array::from(vec![5., 4., 3., 2., 1.]); 26 | 27 | let z = a + b; 28 | let w = &c + &d; 29 | 30 | assert_abs_diff_eq!(z, Array::from(vec![6., 6., 6., 6., 6.])); 31 | 32 | println!("c = {}", c); 33 | c[0] = 10.; 34 | d[1] = 10.; 35 | 36 | assert_abs_diff_eq!(w, Array::from(vec![6., 6., 6., 6., 6.])); 37 | 38 | } 39 | ``` 40 | 41 | [`approx`]: https://docs.rs/approx/*/approx/index.html 42 | [`assert_abs_diff_eq!`]: https://docs.rs/approx/*/approx/macro.assert_abs_diff_eq.html 43 | [Binary Operators With Two Arrays]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#binary-operators-with-two-arrays 44 | [ndarray]: https://docs.rs/crate/ndarray/* 45 | [`ndarray::Array`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html 46 | -------------------------------------------------------------------------------- /src/datetime/duration/checked.md: -------------------------------------------------------------------------------- 1 | ## 执行日期检查和时间计算 2 | 3 | 8 | 9 | [![chrono-badge]][chrono] [![cat-date-and-time-badge]][cat-date-and-time] 10 | 11 | 使用 [`DateTime::checked_add_signed`] 计算并显示两周之后的日期和时间,使用 [`DateTime::checked_sub_signed`] 计算并显示前一天的日期。如果无法计算出日期和时间,这些方法将返回 None。 12 | 13 | 可以在 [`chrono::format::strftime`] 中找到适用于 [`DateTime::format`] 的转义序列。 14 | 15 | ```rust,edition2018 16 | use chrono::{DateTime, Duration, Utc}; 17 | 18 | fn day_earlier(date_time: DateTime) -> Option> { 19 | date_time.checked_sub_signed(Duration::days(1)) 20 | } 21 | 22 | fn main() { 23 | let now = Utc::now(); 24 | println!("{}", now); 25 | 26 | let almost_three_weeks_from_now = now.checked_add_signed(Duration::weeks(2)) 27 | .and_then(|in_2weeks| in_2weeks.checked_add_signed(Duration::weeks(1))) 28 | .and_then(day_earlier); 29 | 30 | match almost_three_weeks_from_now { 31 | Some(x) => println!("{}", x), 32 | None => eprintln!("Almost three weeks from now overflows!"), 33 | } 34 | 35 | match now.checked_add_signed(Duration::max_value()) { 36 | Some(x) => println!("{}", x), 37 | None => eprintln!("We can't use chrono to tell the time for the Solar System to complete more than one full orbit around the galactic center."), 38 | } 39 | } 40 | ``` 41 | 42 | [`chrono::format::strftime`]: https://docs.rs/chrono/*/chrono/format/strftime/index.html 43 | [`DateTime::checked_add_signed`]: https://docs.rs/chrono/*/chrono/struct.Date.html#method.checked_add_signed 44 | [`DateTime::checked_sub_signed`]: https://docs.rs/chrono/*/chrono/struct.Date.html#method.checked_sub_signed 45 | [`DateTime::format`]: https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.format 46 | -------------------------------------------------------------------------------- /src/os/external/process-output.md: -------------------------------------------------------------------------------- 1 | ## 运行外部命令并处理 stdout 2 | 3 | 8 | 9 | [![regex-badge]][regex] [![cat-os-badge]][cat-os] [![cat-text-processing-badge]][cat-text-processing] 10 | 11 | 将 `git log --oneline` 作为外部命令 [`Command`] 运行,并使用 [`Regex`] 检查其 [`Output`],以获取最后 5 次提交的哈希值和消息。 12 | 13 | ```rust,edition2018,no_run 14 | # use error_chain::error_chain; 15 | 16 | use std::process::Command; 17 | use regex::Regex; 18 | # 19 | # error_chain!{ 20 | # foreign_links { 21 | # Io(std::io::Error); 22 | # Regex(regex::Error); 23 | # Utf8(std::string::FromUtf8Error); 24 | # } 25 | # } 26 | 27 | #[derive(PartialEq, Default, Clone, Debug)] 28 | struct Commit { 29 | hash: String, 30 | message: String, 31 | } 32 | 33 | fn main() -> Result<()> { 34 | let output = Command::new("git").arg("log").arg("--oneline").output()?; 35 | 36 | if !output.status.success() { 37 | error_chain::bail!("Command executed with failing error code"); 38 | } 39 | 40 | let pattern = Regex::new(r"(?x) 41 | ([0-9a-fA-F]+) # 提交的哈希值 42 | (.*) # 提交信息")?; 43 | 44 | String::from_utf8(output.stdout)? 45 | .lines() 46 | .filter_map(|line| pattern.captures(line)) 47 | .map(|cap| { 48 | Commit { 49 | hash: cap[1].to_string(), 50 | message: cap[2].trim().to_string(), 51 | } 52 | }) 53 | .take(5) 54 | .for_each(|x| println!("{:?}", x)); 55 | 56 | Ok(()) 57 | } 58 | ``` 59 | 60 | [`Command`]: https://doc.rust-lang.org/std/process/struct.Command.html 61 | [`Output`]: https://doc.rust-lang.org/std/process/struct.Output.html 62 | [`Regex`]: https://docs.rs/regex/*/regex/struct.Regex.html 63 | -------------------------------------------------------------------------------- /src/web/clients/download/post-file.md: -------------------------------------------------------------------------------- 1 | ## POST 文件到 paste-rs 2 | 3 | 8 | 9 | [![reqwest-badge]][reqwest] [![cat-net-badge]][cat-net] 10 | 11 | 本实例使用 [`reqwest::Client`] 建立与 https://paste.rs 的连接,遵循 [`reqwest::RequestBuilder`] 结构体模式。调用 [`Client::post`] 方法,以 URL 为参数连接目标,[`RequestBuilder::body`] 通过读取文件设置要发送的内容,[`RequestBuilder::send`] 方法在文件上传过程中将一直阻塞,直到返回响应消息。最后,[`read_to_string`] 返回响应消息并显示在控制台中。 12 | 13 | ```rust,edition2018,no_run 14 | use error_chain::error_chain; 15 | use std::fs::File; 16 | use std::io::Read; 17 | 18 | error_chain! { 19 | foreign_links { 20 | HttpRequest(reqwest::Error); 21 | IoError(::std::io::Error); 22 | } 23 | } 24 | #[tokio::main] 25 | 26 | async fn main() -> Result<()> { 27 | let paste_api = "https://paste.rs"; 28 | let mut file = File::open("message")?; 29 | 30 | let mut contents = String::new(); 31 | file.read_to_string(&mut contents)?; 32 | 33 | let client = reqwest::Client::new(); 34 | let res = client.post(paste_api) 35 | .body(contents) 36 | .send() 37 | .await?; 38 | let response_text = res.text().await?; 39 | println!("Your paste is located at: {}",response_text ); 40 | Ok(()) 41 | } 42 | ``` 43 | 44 | [`Client::post`]: https://docs.rs/reqwest/*/reqwest/struct.Client.html#method.post 45 | [`read_to_string`]: https://doc.rust-lang.org/std/io/trait.Read.html#method.read_to_string 46 | [`RequestBuilder::body`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html#method.body 47 | [`RequestBuilder::send`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html#method.send 48 | [`reqwest::Client`]: https://docs.rs/reqwest/*/reqwest/struct.Client.html 49 | [`reqwest::RequestBuilder`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html 50 | -------------------------------------------------------------------------------- /src/development_tools.md: -------------------------------------------------------------------------------- 1 | # 开发工具 2 | 3 | 8 | 9 | {{#include development_tools/debugging.md}} 10 | 11 | ## 版本控制 12 | 13 | | 实例名称 | Crates | 类别 | 14 | |--------|--------|------------| 15 | | [解析并递增版本字符串][ex-semver-increment] | [![semver-badge]][semver] | [![cat-config-badge]][cat-config] | 16 | | [解析复杂的版本字符串][ex-semver-complex] | [![semver-badge]][semver] | [![cat-config-badge]][cat-config] | 17 | | [检查给定版本是否为预发布版本][ex-semver-prerelease] | [![semver-badge]][semver] | [![cat-config-badge]][cat-config] | 18 | | [查询适配给定范围的最新版本][ex-semver-latest] | [![semver-badge]][semver] | [![cat-config-badge]][cat-config] | 19 | | [检查外部命令的版本兼容性][ex-semver-command] | [![semver-badge]][semver] | [![cat-text-processing-badge]][cat-text-processing] [![cat-os-badge]][cat-os] 20 | 21 | ## 构建时 22 | 23 | | 实例名称 | Crates | 类别 | 24 | |--------|--------|------------| 25 | | [编译并静态链接到绑定的 C 语言库][ex-cc-static-bundled] | [![cc-badge]][cc] | [![cat-development-tools-badge]][cat-development-tools] | 26 | | [编译并静态链接到绑定的 C++ 语言库][ex-cc-static-bundled-cpp] | [![cc-badge]][cc] | [![cat-development-tools-badge]][cat-development-tools] | 27 | | [编译 C 语言库时自定义设置][ex-cc-custom-defines] | [![cc-badge]][cc] | [![cat-development-tools-badge]][cat-development-tools] | 28 | 29 | [ex-semver-increment]: development_tools/versioning.md#解析并递增版本字符串 30 | [ex-semver-complex]: development_tools/versioning.md#解析复杂的版本字符串 31 | [ex-semver-prerelease]: development_tools/versioning.md#检查给定版本是否为预发布版本 32 | [ex-semver-latest]: development_tools/versioning.md#查询适配给定范围的最新版本 33 | [ex-semver-command]: development_tools/versioning.md#检查外部命令的版本兼容性 34 | 35 | [ex-cc-static-bundled]: development_tools/build_tools.md#编译并静态链接到绑定的-c-语言库 36 | [ex-cc-static-bundled-cpp]: development_tools/build_tools.md#编译并静态链接到绑定的-c-语言库-1 37 | [ex-cc-custom-defines]: development_tools/build_tools.md#编译-c-语言库时自定义设置 38 | 39 | {{#include links.md}} 40 | -------------------------------------------------------------------------------- /src/web/clients/api/rest-head.md: -------------------------------------------------------------------------------- 1 | ## 检查 API 资源是否存在 2 | 3 | 8 | 9 | [![reqwest-badge]][reqwest] [![cat-net-badge]][cat-net] 10 | 11 | 使用消息标头 HEAD 请求(([`Client::head`])查询 GitHub 用户端接口,然后检查响应代码以确定是否成功。这是一种无需接收 HTTP 响应消息主体,即可快速查询 rest 资源的方法。使用 [`ClientBuilder::timeout`] 方法配置的 [`reqwest::Client`] 结构体将确保请求不会超时。 12 | 13 | 由于 [`ClientBuilder::build`] 和 [`RequestBuilder::send`] 都返回错误类型 [`reqwest::Error`],所以便捷的 [`reqwest::Result`] 类型被用于主函数的返回类型。 14 | 15 | ```rust,edition2018,no_run 16 | use reqwest::Result; 17 | use std::time::Duration; 18 | use reqwest::ClientBuilder; 19 | 20 | #[tokio::main] 21 | async fn main() -> Result<()> { 22 | let user = "ferris-the-crab"; 23 | let request_url = format!("https://api.github.com/users/{}", user); 24 | println!("{}", request_url); 25 | 26 | let timeout = Duration::new(5, 0); 27 | let client = ClientBuilder::new().timeout(timeout).build()?; 28 | let response = client.head(&request_url).send().await?; 29 | 30 | if response.status().is_success() { 31 | println!("{} is a user!", user); 32 | } else { 33 | println!("{} is not a user!", user); 34 | } 35 | 36 | Ok(()) 37 | } 38 | ``` 39 | 40 | [`ClientBuilder::build`]: https://docs.rs/reqwest/*/reqwest/struct.ClientBuilder.html#method.build 41 | [`Client::head`]: https://docs.rs/reqwest/*/reqwest/struct.Client.html#method.head 42 | [`ClientBuilder::timeout`]: https://docs.rs/reqwest/*/reqwest/struct.ClientBuilder.html#method.timeout 43 | [`RequestBuilder::send`]: https://docs.rs/reqwest/*/reqwest/struct.RequestBuilder.html#method.send 44 | [`reqwest::Client`]: https://docs.rs/reqwest/*/reqwest/struct.Client.html 45 | [`reqwest::Error`]: https://docs.rs/reqwest/*/reqwest/struct.Error.html 46 | [`reqwest::Result`]:https://docs.rs/reqwest/*/reqwest/type.Result.html 47 | -------------------------------------------------------------------------------- /src/cli/ansi_terminal/ansi_term-basic.md: -------------------------------------------------------------------------------- 1 | ## ANSI 终端 2 | 3 | 8 | 9 | [![ansi_term-badge]][ansi_term] [![cat-command-line-badge]][cat-command-line] 10 | 11 | 此程序描述了 [`ansi_term`] crate 的使用方法,以及它如何用于控制 ANSI 终端上的颜色和格式,如蓝色粗体文本或黄色下划线文本。 12 | 13 | [`ansi_term`] 中有两种主要的数据结构:[`ANSIString`] 和 [`Style`]。[`Style`] 包含样式信息:颜色,是否粗体文本,或者是否闪烁,或者其它样式。还有 Colour 变量,代表简单的前景色样式。[`ANSIString`] 是与 [`Style`] 配对的字符串。 14 | 15 | **注意**:英式英语中使用 *Colour* 而不是 *Color*,不要混淆。 16 | 17 | ### 打印彩色文本到终端 18 | 19 | ```rust,edition2018 20 | use ansi_term::Colour; 21 | 22 | fn main() { 23 | println!("This is {} in color, {} in color and {} in color", 24 | Colour::Red.paint("red"), 25 | Colour::Blue.paint("blue"), 26 | Colour::Green.paint("green")); 27 | } 28 | ``` 29 | 30 | ### 终端中的粗体文本 31 | 32 | 对于比简单的前景色变化更复杂的事情,代码需要构造 `Style` 结构体。[`Style::new()`] 创建结构体,并链接属性。 33 | 34 | ```rust,edition2018 35 | use ansi_term::Style; 36 | 37 | fn main() { 38 | println!("{} and this is not", 39 | Style::new().bold().paint("This is Bold")); 40 | } 41 | ``` 42 | ### 终端中的粗体和彩色文本 43 | 44 | `Colour` 模块实现了许多类似 `Style` 的函数,并且可以链接方法。 45 | 46 | ```rust,edition2018 47 | use ansi_term::Colour; 48 | use ansi_term::Style; 49 | 50 | fn main(){ 51 | println!("{}, {} and {}", 52 | Colour::Yellow.paint("This is colored"), 53 | Style::new().bold().paint("this is bold"), 54 | Colour::Yellow.bold().paint("this is bold and colored")); 55 | } 56 | ``` 57 | 58 | [documentation]: https://docs.rs/ansi_term/ 59 | [`ansi_term`]: https://crates.io/crates/ansi_term 60 | [`ANSIString`]: https://docs.rs/ansi_term/*/ansi_term/type.ANSIString.html 61 | [`Style`]: https://docs.rs/ansi_term/*/ansi_term/struct.Style.html 62 | [`Style::new()`]: https://docs.rs/ansi_term/0.11.0/ansi_term/struct.Style.html#method.new 63 | -------------------------------------------------------------------------------- /src/database/postgres/insert_query_data.md: -------------------------------------------------------------------------------- 1 | ## 数据插入和查询 2 | 3 | 8 | 9 | [![postgres-badge]][postgres] [![cat-database-badge]][cat-database] 10 | 11 | 下述实例中使用 `Client` 的 [`execute`] 方法将数据插入到 `author` 表中。然后,使用 `Client` 的 [`query`] 方法查询 `author` 表中的数据。 12 | 13 | ```rust,edition2018,no_run 14 | use postgres::{Client, NoTls, Error}; 15 | use std::collections::HashMap; 16 | 17 | struct Author { 18 | _id: i32, 19 | name: String, 20 | country: String 21 | } 22 | 23 | fn main() -> Result<(), Error> { 24 | let mut client = Client::connect("postgresql://postgres:postgres@localhost/library", 25 | NoTls)?; 26 | 27 | let mut authors = HashMap::new(); 28 | authors.insert(String::from("Chinua Achebe"), "Nigeria"); 29 | authors.insert(String::from("Rabindranath Tagore"), "India"); 30 | authors.insert(String::from("Anita Nair"), "India"); 31 | 32 | for (key, value) in &authors { 33 | let author = Author { 34 | _id: 0, 35 | name: key.to_string(), 36 | country: value.to_string() 37 | }; 38 | 39 | client.execute( 40 | "INSERT INTO author (name, country) VALUES ($1, $2)", 41 | &[&author.name, &author.country], 42 | )?; 43 | } 44 | 45 | for row in client.query("SELECT id, name, country FROM author", &[])? { 46 | let author = Author { 47 | _id: row.get(0), 48 | name: row.get(1), 49 | country: row.get(2), 50 | }; 51 | println!("Author {} is from {}", author.name, author.country); 52 | } 53 | 54 | Ok(()) 55 | 56 | } 57 | ``` 58 | 59 | [`execute`]: https://docs.rs/postgres/0.17.2/postgres/struct.Client.html#method.execute 60 | [`query`]: https://docs.rs/postgres/0.17.2/postgres/struct.Client.html#method.query 61 | -------------------------------------------------------------------------------- /src/development_tools/debugging/config_log/log-custom.md: -------------------------------------------------------------------------------- 1 | ## 将信息记录到自定义位置 2 | 3 | 8 | 9 | [![log-badge]][log] [![log4rs-badge]][log4rs] [![cat-debugging-badge]][cat-debugging] 10 | 11 | [log4rs] 将日志输出配置到自定义位置。[log4rs] 可以使用外部 YAML 文件或生成器配置。 12 | 13 | 使用文件附加器 [`log4rs::append::file::FileAppender`] 创建日志配置,文件附加器定义日志记录的目标位置。日志配置使用 [`log4rs::encode::pattern`] 中的自定义模式进行编码,将配置项分配给 [`log4rs::config::Config`],并设置默认的日志等级 [`log::LevelFilter`]。 14 | 15 | ```rust,edition2018,no_run 16 | # use error_chain::error_chain; 17 | 18 | use log::LevelFilter; 19 | use log4rs::append::file::FileAppender; 20 | use log4rs::encode::pattern::PatternEncoder; 21 | use log4rs::config::{Appender, Config, Root}; 22 | # 23 | # error_chain! { 24 | # foreign_links { 25 | # Io(std::io::Error); 26 | # LogConfig(log4rs::config::Errors); 27 | # SetLogger(log::SetLoggerError); 28 | # } 29 | # } 30 | 31 | fn main() -> Result<()> { 32 | let logfile = FileAppender::builder() 33 | .encoder(Box::new(PatternEncoder::new("{l} - {m}\n"))) 34 | .build("log/output.log")?; 35 | 36 | let config = Config::builder() 37 | .appender(Appender::builder().build("logfile", Box::new(logfile))) 38 | .build(Root::builder() 39 | .appender("logfile") 40 | .build(LevelFilter::Info))?; 41 | 42 | log4rs::init_config(config)?; 43 | 44 | log::info!("Hello, world!"); 45 | 46 | Ok(()) 47 | } 48 | ``` 49 | 50 | [`log4rs::append::file::FileAppender`]: https://docs.rs/log4rs/*/log4rs/append/file/struct.FileAppender.html 51 | [`log4rs::config::Config`]: https://docs.rs/log4rs/*/log4rs/config/struct.Config.html 52 | [`log4rs::encode::pattern`]: https://docs.rs/log4rs/*/log4rs/encode/pattern/index.html 53 | [`log::LevelFilter`]: https://docs.rs/log/*/log/enum.LevelFilter.html 54 | -------------------------------------------------------------------------------- /src/data_structures/bitfield/bitfield.md: -------------------------------------------------------------------------------- 1 | ## 定义并操作位域风格的类型 2 | 3 | 8 | 9 | [![bitflags-badge]][bitflags] [![cat-no-std-badge]][cat-no-std] 10 | 11 | 如下实例在 [`bitflags!`] 宏的帮助下创建类型安全的位域类型 `MyFlags`,并为其实现基本的`清理`操作(`clear` 方法)以及 [`Display`] trait。随后,展示了基本的按位操作和格式化。 12 | 13 | ```rust,edition2018 14 | use bitflags::bitflags; 15 | use std::fmt; 16 | 17 | bitflags! { 18 | struct MyFlags: u32 { 19 | const FLAG_A = 0b00000001; 20 | const FLAG_B = 0b00000010; 21 | const FLAG_C = 0b00000100; 22 | const FLAG_ABC = Self::FLAG_A.bits 23 | | Self::FLAG_B.bits 24 | | Self::FLAG_C.bits; 25 | } 26 | } 27 | 28 | impl MyFlags { 29 | pub fn clear(&mut self) -> &mut MyFlags { 30 | self.bits = 0; 31 | self 32 | } 33 | } 34 | 35 | impl fmt::Display for MyFlags { 36 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 37 | write!(f, "{:032b}", self.bits) 38 | } 39 | } 40 | 41 | fn main() { 42 | let e1 = MyFlags::FLAG_A | MyFlags::FLAG_C; 43 | let e2 = MyFlags::FLAG_B | MyFlags::FLAG_C; 44 | assert_eq!((e1 | e2), MyFlags::FLAG_ABC); 45 | assert_eq!((e1 & e2), MyFlags::FLAG_C); 46 | assert_eq!((e1 - e2), MyFlags::FLAG_A); 47 | assert_eq!(!e2, MyFlags::FLAG_A); 48 | 49 | let mut flags = MyFlags::FLAG_ABC; 50 | assert_eq!(format!("{}", flags), "00000000000000000000000000000111"); 51 | assert_eq!(format!("{}", flags.clear()), "00000000000000000000000000000000"); 52 | assert_eq!(format!("{:?}", MyFlags::FLAG_B), "FLAG_B"); 53 | assert_eq!(format!("{:?}", MyFlags::FLAG_A | MyFlags::FLAG_B), "FLAG_A | FLAG_B"); 54 | } 55 | ``` 56 | 57 | [`bitflags!`]: https://docs.rs/bitflags/*/bitflags/macro.bitflags.html 58 | [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html 59 | -------------------------------------------------------------------------------- /src/algorithms/sorting/sort_struct.md: -------------------------------------------------------------------------------- 1 | ## 结构体 Vector 排序 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-science-badge]][cat-science] 10 | 11 | 依据自然顺序(按名称和年龄),对具有 `name` 和 `age` 属性的 Person 结构体 Vector 排序。为了使 Person 可排序,你需要四个 traits:[`Eq`]、[`PartialEq`]、[`Ord`],以及 [`PartialOrd`]。这些 traits 可以被简单地派生。你也可以使用 [`vec:sort_by`] 方法自定义比较函数,仅按照年龄排序。 12 | 13 | ```rust,edition2018 14 | #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] 15 | struct Person { 16 | name: String, 17 | age: u32 18 | } 19 | 20 | impl Person { 21 | pub fn new(name: String, age: u32) -> Self { 22 | Person { 23 | name, 24 | age 25 | } 26 | } 27 | } 28 | 29 | fn main() { 30 | let mut people = vec![ 31 | Person::new("Zoe".to_string(), 25), 32 | Person::new("Al".to_string(), 60), 33 | Person::new("John".to_string(), 1), 34 | ]; 35 | 36 | // 根据获得的自然顺序(name 和 age)对 people 进行排序 37 | people.sort(); 38 | 39 | assert_eq!( 40 | people, 41 | vec![ 42 | Person::new("Al".to_string(), 60), 43 | Person::new("John".to_string(), 1), 44 | Person::new("Zoe".to_string(), 25), 45 | ]); 46 | 47 | // 根据 age 值对 people 进行排序 48 | people.sort_by(|a, b| b.age.cmp(&a.age)); 49 | 50 | assert_eq!( 51 | people, 52 | vec![ 53 | Person::new("Al".to_string(), 60), 54 | Person::new("Zoe".to_string(), 25), 55 | Person::new("John".to_string(), 1), 56 | ]); 57 | 58 | } 59 | ``` 60 | 61 | [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html 62 | [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html 63 | [`Ord`]: https://doc.rust-lang.org/std/cmp/trait.Ord.html 64 | [`PartialOrd`]: https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html 65 | [`vec:sort_by`]: https://doc.rust-lang.org/std/vec/struct.Vec.html#method.sort_by 66 | -------------------------------------------------------------------------------- /src/concurrency/parallel/rayon-map-reduce.md: -------------------------------------------------------------------------------- 1 | ## Map-reduce 并行计算 2 | 3 | 8 | 9 | [![rayon-badge]][rayon] [![cat-concurrency-badge]][cat-concurrency] 10 | 11 | 此实例使用 [`rayon::filter`]、[`rayon::map`],以及 [`rayon::reduce`] 计算 `Person` 对象中年龄超过 30 岁的那些人的平均年龄。 12 | 13 | [`rayon::filter`] 过滤集合中满足给定断言的元素。[`rayon::map`] 对每个元素执行一次计算,创建一个新的迭代;然后,基于前一次的 reduce 计算结果和当前元素一起,[`rayon::reduce`] 执行新的计算。也可以查看 [`rayon::sum`],它与本实例中的 reduce 计算具有相同的结果。 14 | 15 | ```rust,edition2018 16 | use rayon::prelude::*; 17 | 18 | struct Person { 19 | age: u32, 20 | } 21 | 22 | fn main() { 23 | let v: Vec = vec![ 24 | Person { age: 23 }, 25 | Person { age: 19 }, 26 | Person { age: 42 }, 27 | Person { age: 17 }, 28 | Person { age: 17 }, 29 | Person { age: 31 }, 30 | Person { age: 30 }, 31 | ]; 32 | 33 | let num_over_30 = v.par_iter().filter(|&x| x.age > 30).count() as f32; 34 | let sum_over_30 = v.par_iter() 35 | .map(|x| x.age) 36 | .filter(|&x| x > 30) 37 | .reduce(|| 0, |x, y| x + y); 38 | 39 | let alt_sum_30: u32 = v.par_iter() 40 | .map(|x| x.age) 41 | .filter(|&x| x > 30) 42 | .sum(); 43 | 44 | let avg_over_30 = sum_over_30 as f32 / num_over_30; 45 | let alt_avg_over_30 = alt_sum_30 as f32/ num_over_30; 46 | 47 | assert!((avg_over_30 - alt_avg_over_30).abs() < std::f32::EPSILON); 48 | println!("The average age of people older than 30 is {}", avg_over_30); 49 | } 50 | ``` 51 | 52 | [`rayon::filter`]: https://docs.rs/rayon/*/rayon/iter/trait.ParallelIterator.html#method.filter 53 | [`rayon::map`]: https://docs.rs/rayon/*/rayon/iter/trait.ParallelIterator.html#method.map 54 | [`rayon::reduce`]: https://docs.rs/rayon/*/rayon/iter/trait.ParallelIterator.html#method.reduce 55 | [`rayon::sum`]: https://docs.rs/rayon/*/rayon/iter/trait.ParallelIterator.html#method.sum 56 | -------------------------------------------------------------------------------- /src/development_tools/versioning/semver-latest.md: -------------------------------------------------------------------------------- 1 | ## 查询适配给定范围的最新版本 2 | 3 | 8 | 9 | [![semver-badge]][semver] [![cat-config-badge]][cat-config] 10 | 11 | 给定一个版本字符串 &str 的列表,查找最新的语义化版本 [`semver::Version`]。[`semver::VersionReq`] 用 [`VersionReq::matches`] 过滤列表,也可以展示语义化版本 `semver` 的预发布参数设置。 12 | 13 | ```rust,edition2018 14 | # use error_chain::error_chain; 15 | 16 | use semver::{Version, VersionReq}; 17 | # 18 | # error_chain! { 19 | # foreign_links { 20 | # SemVer(semver::SemVerError); 21 | # SemVerReq(semver::ReqParseError); 22 | # } 23 | # } 24 | 25 | fn find_max_matching_version<'a, I>(version_req_str: &str, iterable: I) -> Result> 26 | where 27 | I: IntoIterator, 28 | { 29 | let vreq = VersionReq::parse(version_req_str)?; 30 | 31 | Ok( 32 | iterable 33 | .into_iter() 34 | .filter_map(|s| Version::parse(s).ok()) 35 | .filter(|s| vreq.matches(s)) 36 | .max(), 37 | ) 38 | } 39 | 40 | fn main() -> Result<()> { 41 | assert_eq!( 42 | find_max_matching_version("<= 1.0.0", vec!["0.9.0", "1.0.0", "1.0.1"])?, 43 | Some(Version::parse("1.0.0")?) 44 | ); 45 | 46 | assert_eq!( 47 | find_max_matching_version( 48 | ">1.2.3-alpha.3", 49 | vec![ 50 | "1.2.3-alpha.3", 51 | "1.2.3-alpha.4", 52 | "1.2.3-alpha.10", 53 | "1.2.3-beta.4", 54 | "3.4.5-alpha.9", 55 | ] 56 | )?, 57 | Some(Version::parse("1.2.3-beta.4")?) 58 | ); 59 | 60 | Ok(()) 61 | } 62 | ``` 63 | 64 | [`semver::Version`]: https://docs.rs/semver/*/semver/struct.Version.html 65 | [`semver::VersionReq`]: https://docs.rs/semver/*/semver/struct.VersionReq.html 66 | [`VersionReq::matches`]: https://docs.rs/semver/*/semver/struct.VersionReq.html#method.matches 67 | -------------------------------------------------------------------------------- /src/science/mathematics/linear_algebra/vector-norm.md: -------------------------------------------------------------------------------- 1 | ## Vector 范数 2 | 3 | 8 | 9 | [![ndarray-badge]][ndarray] 10 | 11 | 这个实例展示了 [`Array1`] 类型、[`ArrayView1`] 类型、[`fold`] 方法,以及 [`dot`] 方法在计算给定 vector 的 [l1] 和 [l2] 范数时的用法。 12 | + `l2_norm` 函数是两者中较简单的,它计算一个 vector 与自身的点积(dot product,数量积)的平方根。 13 | + `l1_norm` 函数通过 `fold` 运算来计算元素的绝对值(也可以通过 `x.mapv(f64::abs).scalar_sum()` 执行,但是会为 `mapv` 的结果分配一个新的数组)。 14 | 15 | 请注意:`l1_norm` 和 `l2_norm` 都采用 [`ArrayView1`] 类型。这个实例考虑了 vector 范数,所以范数函数只需要接受一维视图([`ArrayView1`])。虽然函数可以使用类型为 `&Array1` 的参数,但这将要求调用方引用拥有所有权的数组,这比访问视图更为严格(因为视图可以从任意数组或视图创建,而不仅仅是从拥有所有权的数组创建)。 16 | 17 | `Array` 和 `ArrayView` 都是 `ArrayBase` 的类型别名。于是,大多数的调用方参数类型可以是 `&ArrayBase where S: Data`,这样调用方就可以使用 `&array` 或者 `&view` 而不是 `x.view()`。如果该函数是公共 API 的一部分,那么对于用户来说,这可能是一个更好的选择。对于内部函数,更简明的 `ArrayView1` 或许更合适。 18 | 19 | ```rust,edition2018 20 | use ndarray::{array, Array1, ArrayView1}; 21 | 22 | fn l1_norm(x: ArrayView1) -> f64 { 23 | x.fold(0., |acc, elem| acc + elem.abs()) 24 | } 25 | 26 | fn l2_norm(x: ArrayView1) -> f64 { 27 | x.dot(&x).sqrt() 28 | } 29 | 30 | fn normalize(mut x: Array1) -> Array1 { 31 | let norm = l2_norm(x.view()); 32 | x.mapv_inplace(|e| e/norm); 33 | x 34 | } 35 | 36 | fn main() { 37 | let x = array![1., 2., 3., 4., 5.]; 38 | println!("||x||_2 = {}", l2_norm(x.view())); 39 | println!("||x||_1 = {}", l1_norm(x.view())); 40 | println!("Normalizing x yields {:?}", normalize(x)); 41 | } 42 | ``` 43 | 44 | [`Array1`]: https://docs.rs/ndarray/*/ndarray/type.Array1.html 45 | [`ArrayView1`]: https://docs.rs/ndarray/*/ndarray/type.ArrayView1.html 46 | [`dot`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.dot 47 | [`fold`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.fold 48 | [l1]: http://mathworld.wolfram.com/L1-Norm.html 49 | [l2]: http://mathworld.wolfram.com/L2-Norm.html 50 | -------------------------------------------------------------------------------- /src/os/external/piped.md: -------------------------------------------------------------------------------- 1 | ## 运行管道传输的外部命令 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-os-badge]][cat-os] 10 | 11 | 显示当前工作目录中前 10 大的文件和子目录,它等同于运行: `du -ah . | 12 | sort -hr | head -n 10`。 13 | 14 | 每个命令 [`Command`] 代表一个进程,子进程的输出是通过父进程和子进程之间的管道 [`Stdio::piped`] 捕获的。 15 | 16 | ```rust,edition2018,no_run 17 | # use error_chain::error_chain; 18 | # 19 | use std::process::{Command, Stdio}; 20 | # 21 | # error_chain! { 22 | # foreign_links { 23 | # Io(std::io::Error); 24 | # Utf8(std::string::FromUtf8Error); 25 | # } 26 | # } 27 | 28 | fn main() -> Result<()> { 29 | let directory = std::env::current_dir()?; 30 | let mut du_output_child = Command::new("du") 31 | .arg("-ah") 32 | .arg(&directory) 33 | .stdout(Stdio::piped()) 34 | .spawn()?; 35 | 36 | if let Some(du_output) = du_output_child.stdout.take() { 37 | let mut sort_output_child = Command::new("sort") 38 | .arg("-hr") 39 | .stdin(du_output) 40 | .stdout(Stdio::piped()) 41 | .spawn()?; 42 | 43 | du_output_child.wait()?; 44 | 45 | if let Some(sort_output) = sort_output_child.stdout.take() { 46 | let head_output_child = Command::new("head") 47 | .args(&["-n", "10"]) 48 | .stdin(sort_output) 49 | .stdout(Stdio::piped()) 50 | .spawn()?; 51 | 52 | let head_stdout = head_output_child.wait_with_output()?; 53 | 54 | sort_output_child.wait()?; 55 | 56 | println!( 57 | "Top 10 biggest files and directories in '{}':\n{}", 58 | directory.display(), 59 | String::from_utf8(head_stdout.stdout).unwrap() 60 | ); 61 | } 62 | } 63 | 64 | Ok(()) 65 | } 66 | ``` 67 | 68 | [`Command`]: https://doc.rust-lang.org/std/process/struct.Command.html 69 | [`Stdio::piped`]: https://doc.rust-lang.org/std/process/struct.Stdio.html 70 | -------------------------------------------------------------------------------- /src/development_tools/debugging/config_log/log-timestamp.md: -------------------------------------------------------------------------------- 1 | ## 在日志信息中包含时间戳 2 | 3 | 8 | 9 | [![log-badge]][log] [![env_logger-badge]][env_logger] [![chrono-badge]][chrono] [![cat-debugging-badge]][cat-debugging] 10 | 11 | 使用 [`Builder`] 创建自定义记录器配置。每个日志项调用 [`Local::now`] 以获取本地时区中的当前 [`DateTime`],并使用 [`DateTime::format`] 和 [`strftime::specifiers`] 来格式化最终日志中使用的时间戳。 12 | 13 | 如下实例调用 [`Builder::format`] 设置一个闭包,该闭包用时间戳、[`Record::level`] 和正文([`Record::args`])对每个信息文本进行格式化。 14 | 15 | ```rust,edition2018 16 | use std::io::Write; 17 | use chrono::Local; 18 | use env_logger::Builder; 19 | use log::LevelFilter; 20 | 21 | fn main() { 22 | Builder::new() 23 | .format(|buf, record| { 24 | writeln!(buf, 25 | "{} [{}] - {}", 26 | Local::now().format("%Y-%m-%dT%H:%M:%S"), 27 | record.level(), 28 | record.args() 29 | ) 30 | }) 31 | .filter(None, LevelFilter::Info) 32 | .init(); 33 | 34 | log::warn!("warn"); 35 | log::info!("info"); 36 | log::debug!("debug"); 37 | } 38 | ``` 39 | 40 | stderr 输入将含有: 41 | 42 | ``` 43 | 2017-05-22T21:57:06 [WARN] - warn 44 | 2017-05-22T21:57:06 [INFO] - info 45 | ``` 46 | 47 | [`DateTime::format`]: https://docs.rs/chrono/*/chrono/struct.DateTime.html#method.format 48 | [`DateTime`]: https://docs.rs/chrono/*/chrono/datetime/struct.DateTime.html 49 | [`Local::now`]: https://docs.rs/chrono/*/chrono/offset/struct.Local.html#method.now 50 | [`Builder`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html 51 | [`Builder::format`]: https://docs.rs/env_logger/*/env_logger/struct.Builder.html#method.format 52 | [`Record::args`]: https://docs.rs/log/*/log/struct.Record.html#method.args 53 | [`Record::level`]: https://docs.rs/log/*/log/struct.Record.html#method.level 54 | [`strftime::specifiers`]: https://docs.rs/chrono/*/chrono/format/strftime/index.html#specifiers 55 | -------------------------------------------------------------------------------- /src/science/mathematics/statistics/standard-deviation.md: -------------------------------------------------------------------------------- 1 | ### 计算标准偏差 2 | 3 | 8 | 9 | [![std-badge]][std] [![cat-science-badge]][cat-science] 10 | 11 | 本实例计算一组测量值的标准偏差和 z 分数(z-score)。 12 | 13 | 标准偏差定义为方差的平方根(用 f32 浮点型的 [`sqrt`] 计算),其中方差是每个测量值与[`平均数`][mean]之间的平方差的[`和`][sum]除以测量次数。 14 | 15 | z 分数(z-score)是指单个测量值偏离数据集[`平均数`][mean]的标准差数。 16 | 17 | ```rust,edition2018 18 | fn mean(data: &[i32]) -> Option { 19 | let sum = data.iter().sum::() as f32; 20 | let count = data.len(); 21 | 22 | match count { 23 | positive if positive > 0 => Some(sum / count as f32), 24 | _ => None, 25 | } 26 | } 27 | 28 | fn std_deviation(data: &[i32]) -> Option { 29 | match (mean(data), data.len()) { 30 | (Some(data_mean), count) if count > 0 => { 31 | let variance = data.iter().map(|value| { 32 | let diff = data_mean - (*value as f32); 33 | 34 | diff * diff 35 | }).sum::() / count as f32; 36 | 37 | Some(variance.sqrt()) 38 | }, 39 | _ => None 40 | } 41 | } 42 | 43 | fn main() { 44 | let data = [3, 1, 6, 1, 5, 8, 1, 8, 10, 11]; 45 | 46 | let data_mean = mean(&data); 47 | println!("Mean is {:?}", data_mean); 48 | 49 | let data_std_deviation = std_deviation(&data); 50 | println!("Standard deviation is {:?}", data_std_deviation); 51 | 52 | let zscore = match (data_mean, data_std_deviation) { 53 | (Some(mean), Some(std_deviation)) => { 54 | let diff = data[4] as f32 - mean; 55 | 56 | Some(diff / std_deviation) 57 | }, 58 | _ => None 59 | }; 60 | println!("Z-score of data at index 4 (with value {}) is {:?}", data[4], zscore); 61 | } 62 | ``` 63 | 64 | [sqrt]: https://doc.rust-lang.org/std/primitive.f32.html#method.sqrt 65 | [sum]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum 66 | [mean]: #集中趋势度量 67 | -------------------------------------------------------------------------------- /src/encoding/complex/toml.md: -------------------------------------------------------------------------------- 1 | ## 反序列化 TOML 配置文件 2 | 3 | 8 | 9 | [![toml-badge]][toml] [![cat-encoding-badge]][cat-encoding] 10 | 11 | 将一些 TOML 配置项解析为一个通用的值 `toml::Value`,该值能够表示任何有效的 TOML 数据。 12 | 13 | ```rust,edition2018 14 | use toml::{Value, de::Error}; 15 | 16 | fn main() -> Result<(), Error> { 17 | let toml_content = r#" 18 | [package] 19 | name = "your_package" 20 | version = "0.1.0" 21 | authors = ["You! "] 22 | 23 | [dependencies] 24 | serde = "1.0" 25 | "#; 26 | 27 | let package_info: Value = toml::from_str(toml_content)?; 28 | 29 | assert_eq!(package_info["dependencies"]["serde"].as_str(), Some("1.0")); 30 | assert_eq!(package_info["package"]["name"].as_str(), 31 | Some("your_package")); 32 | 33 | Ok(()) 34 | } 35 | ``` 36 | 37 | 使用 [Serde] crate 将 TOML 解析为自定义的结构体。 38 | 39 | ```rust,edition2018 40 | use serde::Deserialize; 41 | 42 | use toml::de::Error; 43 | use std::collections::HashMap; 44 | 45 | #[derive(Deserialize)] 46 | struct Config { 47 | package: Package, 48 | dependencies: HashMap, 49 | } 50 | 51 | #[derive(Deserialize)] 52 | struct Package { 53 | name: String, 54 | version: String, 55 | authors: Vec, 56 | } 57 | 58 | fn main() -> Result<(), Error> { 59 | let toml_content = r#" 60 | [package] 61 | name = "your_package" 62 | version = "0.1.0" 63 | authors = ["You! "] 64 | 65 | [dependencies] 66 | serde = "1.0" 67 | "#; 68 | 69 | let package_info: Config = toml::from_str(toml_content)?; 70 | 71 | assert_eq!(package_info.package.name, "your_package"); 72 | assert_eq!(package_info.package.version, "0.1.0"); 73 | assert_eq!(package_info.package.authors, vec!["You! "]); 74 | assert_eq!(package_info.dependencies["serde"], "1.0"); 75 | 76 | Ok(()) 77 | } 78 | ``` 79 | --------------------------------------------------------------------------------