├── projects ├── backyard │ ├── src │ │ ├── garden.rs │ │ ├── garden │ │ │ └── vegetables.rs │ │ └── main.rs │ └── Cargo.toml ├── restaurant │ ├── src │ │ ├── front_of_house.rs │ │ ├── front_of_house │ │ │ └── hosting.rs │ │ └── lib.rs │ └── Cargo.toml ├── io_project │ ├── src │ │ ├── main.rs │ │ └── lib.rs │ └── Cargo.toml ├── my-project │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── aggregator │ ├── src │ │ ├── bin │ │ │ └── test_case.rs │ │ ├── lib.rs │ │ └── main.rs │ └── Cargo.toml ├── associated_type │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── hello_macro │ ├── src │ │ └── lib.rs │ ├── Cargo.toml │ └── hello_macro_derive │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── sp_demos │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── adder │ ├── tests │ │ ├── common │ │ │ └── mod.rs │ │ └── integration_test.rs │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── declarative_macro │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── hello_cargo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── hello_world │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── minigrep │ ├── output.txt │ ├── poem.txt │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ ├── tests.rs │ │ ├── data_structures.rs │ │ └── lib.rs ├── dst │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── guessing_game │ ├── README.md │ ├── Cargo.toml │ └── src │ │ ├── guessing_game.rs │ │ └── main.rs ├── panic_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── variables │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── add │ ├── Cargo.toml │ ├── add_two │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── add_one │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── adder │ │ ├── src │ │ └── main.rs │ │ └── Cargo.toml ├── refutable_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── never_type │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── result_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── cargo_features_demo │ ├── src │ │ ├── tests.rs │ │ ├── main.rs │ │ └── lib.rs │ └── Cargo.toml ├── idomatic_use │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── panic_or_not │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── option_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── while_let_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── rustfix_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── clippy_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── hello-async │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── loops │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── unsafe_functions │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── unsafe_trait │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── improved_guessing_game │ ├── Cargo.toml │ └── src │ │ ├── guessing_game.rs │ │ └── main.rs ├── vec_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── branches │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── functions │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── returning_closure │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── iterator_demo │ ├── src │ │ ├── main.rs │ │ ├── tests.rs │ │ └── lib.rs │ └── Cargo.toml ├── raw_idenitifers │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── ownership_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── enum_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── for_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── data_types │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── fn_pattn_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── art │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── utils.rs │ │ └── kinds.rs ├── hello │ ├── Cargo.toml │ ├── 404.html │ ├── hello.html │ └── src │ │ ├── main.rs │ │ └── lib.rs ├── slices │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── box_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── derive_macro_comsumer │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── mp_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── newtype │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── rc_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── FnMut_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── assert_demo │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── concur_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── extern_code │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── fah_to_cels │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── if_let_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── loop_label │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── match_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── mutex_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── rectangles │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── simple_blog │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── lib.rs ├── simple_gui │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── lib.rs ├── string_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── supertrait │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── tree_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── tuple_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── closure_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── error_handling_demo │ ├── src │ │ └── main.rs │ └── Cargo.toml ├── func_pointer │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── generics_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── hashmap_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── limit_tracker │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── raw_pointers │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── structs_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── type_aliases │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── closure-example │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── cons_list_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── disambiguation │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── drop_func_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── drop_trait_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── lifetimes_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── neo_simple_blog │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── lib.rs ├── ref_cycle_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── references_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── safe_abstraction │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── static_variable │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── closure_move_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── encapsulation_demo │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── hello_macro_derive │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── lyrics_of_xmas_carol │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── operator_overloading │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── pattern_syntax_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── consuming_adaptor_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── closure_captures_demo │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── nth_fibonacci │ ├── Cargo.toml │ └── src │ │ └── main.rs └── traits_demo │ └── src │ └── aggregator │ └── lib.rs ├── .gitignore ├── src ├── Ch21_Appendix.md ├── favicon.png ├── images │ ├── 14-01.png │ ├── 14-02.png │ ├── 14-03.png │ ├── 14-04.png │ ├── 20-01.png │ ├── search-icon.png │ ├── alipay-laxers.jpeg │ ├── rust-fav-icon.png │ ├── wechat-pay-hector.jpeg │ ├── circled-cc.svg │ ├── 15-02.svg │ ├── trpl17-04.svg │ ├── trpl17-05.svg │ ├── 15-01.svg │ ├── trpl17-08.svg │ ├── trpl17-06.svg │ ├── rust-lang-ar21.svg │ └── 15-04.svg ├── appendix │ ├── translations.md │ ├── editions.md │ ├── notes.md │ ├── terminology_list.md │ └── keywords.md ├── Ch01_Getting_Started.md ├── Ch04_Understanding_Ownership.md ├── Ch06_Enums_and_Pattern_Matching.md ├── Ch05_Using_Structs_to_Structure_Related_Data.md ├── 404.md ├── Ch17_Object_Oriented_Programming_Features_of_Rust.md ├── Ch03_Common_Programming_Concepts.md ├── Ch14_More_about_Cargo_and_Crates-io.md ├── crates-io │ ├── custom_commands.md │ ├── release_profiles.md │ └── cargo_install.md ├── Ch08_Common_Collections.md ├── Ch09_Error_Handling.md ├── Ch13_Functional_Language_Features_Iterators_and_Closures.md ├── Ch18_Patterns_and_Matching.md ├── Ch20_Final_Project_Building_a_Multithreaded_Web_Server.md ├── programming_concepts │ └── comments.md ├── Ch19_Advanced_Features.md ├── Ch11_Writing_Automated_Tests.md ├── local_serving.md ├── Ch07_Managing_Growing_Projects_with_Packages_Crates_and_Modules.md ├── Ch12_An_IO_Project_Building_a_Command_Line_Program.md ├── Ch15_Smart_Pointers.md ├── Ch16_Fearless_Concurrency.md ├── packages_crates_and_modules │ ├── packages_and_crates.md │ └── separating_modules.md ├── io_project │ ├── reading_a_file.md │ └── std_err.md ├── concurrency │ └── extensible_concurrency.md ├── functional_features │ └── performance.md ├── favicon.svg ├── Ch16_1_async_programming.md ├── patterns │ └── refutability.md └── Ch10_Generic_Types_Traits_and_Lifetimes.md ├── append_end.sh ├── book.toml └── theme ├── pagetoc.css └── pagetoc.js /projects/backyard/src/garden.rs: -------------------------------------------------------------------------------- 1 | pub mod vegetables; 2 | -------------------------------------------------------------------------------- /projects/restaurant/src/front_of_house.rs: -------------------------------------------------------------------------------- 1 | pub mod hosting; 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | target 3 | Cargo.lock 4 | /index.html 5 | *.tar.gz 6 | pdf 7 | -------------------------------------------------------------------------------- /projects/restaurant/src/front_of_house/hosting.rs: -------------------------------------------------------------------------------- 1 | pub fn add_to_waitlist() {} 2 | -------------------------------------------------------------------------------- /src/Ch21_Appendix.md: -------------------------------------------------------------------------------- 1 | # 附录 2 | 3 | 以下小节包含了在咱们的 Rust 路途中,会发现有用的一些参考资料。 4 | 5 | 6 | -------------------------------------------------------------------------------- /projects/io_project/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /projects/my-project/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /src/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnu4cn/rust-lang-zh_CN/HEAD/src/favicon.png -------------------------------------------------------------------------------- /projects/aggregator/src/bin/test_case.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println! ("媒体聚合器"); 3 | } 4 | -------------------------------------------------------------------------------- /projects/associated_type/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /projects/backyard/src/garden/vegetables.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub struct Asparagus {} 3 | -------------------------------------------------------------------------------- /projects/hello_macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub trait HelloMacro { 2 | fn hello_macro(); 3 | } 4 | -------------------------------------------------------------------------------- /projects/sp_demos/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let x = 5; 3 | let y = &mut x; 4 | } 5 | -------------------------------------------------------------------------------- /src/images/14-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnu4cn/rust-lang-zh_CN/HEAD/src/images/14-01.png -------------------------------------------------------------------------------- /src/images/14-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnu4cn/rust-lang-zh_CN/HEAD/src/images/14-02.png -------------------------------------------------------------------------------- /src/images/14-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnu4cn/rust-lang-zh_CN/HEAD/src/images/14-03.png -------------------------------------------------------------------------------- /src/images/14-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnu4cn/rust-lang-zh_CN/HEAD/src/images/14-04.png -------------------------------------------------------------------------------- /src/images/20-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnu4cn/rust-lang-zh_CN/HEAD/src/images/20-01.png -------------------------------------------------------------------------------- /projects/adder/tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | pub fn setup() { 2 | println! ("特定于库测试的一些设置代码,将放在这里"); 3 | } 4 | -------------------------------------------------------------------------------- /projects/declarative_macro/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | 3 | println!("Hello, world!"); 4 | } 5 | -------------------------------------------------------------------------------- /projects/hello_cargo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // 这是注释。 3 | println! ("Hello, Cargo!"); 4 | } 5 | -------------------------------------------------------------------------------- /projects/hello_world/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // 这是注释。 3 | println!("Hello, World!"); 4 | } 5 | -------------------------------------------------------------------------------- /projects/minigrep/output.txt: -------------------------------------------------------------------------------- 1 | 在文件 poem.txt 中检索:to 2 | Are you nobody, too? 3 | How dreary to be somebody! 4 | -------------------------------------------------------------------------------- /src/appendix/translations.md: -------------------------------------------------------------------------------- 1 | # 附录 F - 本书的一些译本 2 | 3 | <略> 4 | 5 | 6 | 7 | (End) 8 | 9 | 10 | -------------------------------------------------------------------------------- /projects/dst/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let s1: str = "致以问候!"; 3 | let s2: str = "最近过得怎么样?"; 4 | } 5 | -------------------------------------------------------------------------------- /projects/guessing_game/README.md: -------------------------------------------------------------------------------- 1 | # Readme 2 | 3 | 这是一个作为把代码箱上传到 [crates.io](https://crates.io) 示例的 Rust 项目。 4 | -------------------------------------------------------------------------------- /projects/panic_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | 3 | let v = vec! [1, 2, 3]; 4 | 5 | v[99]; 6 | } 7 | -------------------------------------------------------------------------------- /src/images/search-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnu4cn/rust-lang-zh_CN/HEAD/src/images/search-icon.png -------------------------------------------------------------------------------- /projects/variables/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut spaces = " "; 3 | spaces = spaces.len(); 4 | } 5 | -------------------------------------------------------------------------------- /src/images/alipay-laxers.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnu4cn/rust-lang-zh_CN/HEAD/src/images/alipay-laxers.jpeg -------------------------------------------------------------------------------- /src/images/rust-fav-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnu4cn/rust-lang-zh_CN/HEAD/src/images/rust-fav-icon.png -------------------------------------------------------------------------------- /projects/add/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "adder", 5 | "add_one", 6 | "add_two", 7 | ] 8 | -------------------------------------------------------------------------------- /projects/refutable_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if let x = 5 { 3 | println! ("{}", x); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/images/wechat-pay-hector.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnu4cn/rust-lang-zh_CN/HEAD/src/images/wechat-pay-hector.jpeg -------------------------------------------------------------------------------- /projects/io_project/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "io_project" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /projects/never_type/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | print! ("永永 "); 3 | 4 | loop { 5 | print! ("远远 "); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/panic_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "panic_demo" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /projects/result_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "result_demo" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /projects/result_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | 3 | fn main () { 4 | let greeting_file = File::open("hello.txt")?; 5 | } 6 | -------------------------------------------------------------------------------- /projects/cargo_features_demo/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | #[test] 4 | fn five_plus_one() { 5 | assert_eq! (7, add_one(5)); 6 | } 7 | -------------------------------------------------------------------------------- /projects/idomatic_use/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "idomatic_use" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /projects/panic_or_not/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "panic_or_not" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /projects/option_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let x: i8 = 5; 3 | let y: Option = Some(5); 4 | 5 | let sum = x + y; 6 | } 7 | -------------------------------------------------------------------------------- /projects/while_let_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let (x, y) = (1, 2, 3); 3 | 4 | // println! ("x: {}, y: {}, z: {}", x, y, z); 5 | } 6 | -------------------------------------------------------------------------------- /projects/rustfix_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn do_something() {} 2 | 3 | fn main() { 4 | for _i in 0..100 { 5 | do_something(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/clippy_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let x = std::f64::consts::PI; 3 | let r = 8.0; 4 | println!("圆的面积为 {}", x * r * r); 5 | } 6 | -------------------------------------------------------------------------------- /projects/hello-async/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-async" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | trpl = "0.2.0" 8 | -------------------------------------------------------------------------------- /projects/loops/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let a = [10, 20, 30, 40, 50]; 3 | 4 | for el in a { 5 | println! ("the value is: {el}"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/unsafe_functions/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | unsafe fn dangerous() { 3 | println! ("这是一个不安全函数。"); 4 | } 5 | 6 | dangerous(); 7 | } 8 | -------------------------------------------------------------------------------- /projects/unsafe_trait/src/main.rs: -------------------------------------------------------------------------------- 1 | unsafe trait Foo { 2 | // 这里是些方法 3 | } 4 | 5 | unsafe impl Foo for i32 { 6 | // 方法实现在这里 7 | } 8 | 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /projects/improved_guessing_game/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "improved_guessing_game" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | rand = "0.9.1" 8 | -------------------------------------------------------------------------------- /projects/vec_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | 3 | let mut v = vec! [1, 2, 3, 4]; 4 | 5 | let last = v.pop().unwrap(); 6 | 7 | println!("{last}, {:?}", v); 8 | } 9 | -------------------------------------------------------------------------------- /projects/branches/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let condition = true; 3 | let number = if condition { 5 } else { "six" }; 4 | 5 | println! ("number 的值为:{number}"); 6 | } 7 | -------------------------------------------------------------------------------- /projects/functions/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let x = plus_one(5); 3 | 4 | println! ("x 的值为:{x}"); 5 | } 6 | 7 | fn plus_one(x: i32) -> i32 { 8 | x + 1; 9 | } 10 | -------------------------------------------------------------------------------- /projects/returning_closure/src/main.rs: -------------------------------------------------------------------------------- 1 | fn returns_closure() -> Box i32> { 2 | Box::new(|x| x + 1) 3 | } 4 | 5 | fn main() { 6 | println!("Hello, world!"); 7 | } 8 | -------------------------------------------------------------------------------- /projects/idomatic_use/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | fn main() { 4 | let mut map = HashMap::new(); 5 | map.insert(1, 2); 6 | println! ("{:#?}", map); 7 | } 8 | -------------------------------------------------------------------------------- /projects/adder/tests/integration_test.rs: -------------------------------------------------------------------------------- 1 | use adder; 2 | 3 | mod common; 4 | 5 | #[test] 6 | fn it_adds_two() { 7 | common::setup(); 8 | assert_eq! (6, adder::add_two(4)); 9 | } 10 | -------------------------------------------------------------------------------- /projects/iterator_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let v1 = vec! [1, 2, 3]; 3 | 4 | let v2: Vec<_> = v1.iter().map(|x| x + 1).collect(); 5 | 6 | assert_eq! (v2, vec! [2, 3, 4]); 7 | } 8 | -------------------------------------------------------------------------------- /projects/raw_idenitifers/src/main.rs: -------------------------------------------------------------------------------- 1 | fn r#match(needle: &str, haystack: &str) -> bool { 2 | haystack.contains(needle) 3 | } 4 | 5 | fn main() { 6 | assert! (r#match("foo", "foobar")); 7 | } 8 | -------------------------------------------------------------------------------- /projects/backyard/src/main.rs: -------------------------------------------------------------------------------- 1 | use crate::garden::vegetables::Asparagus; 2 | 3 | pub mod garden; 4 | 5 | fn main() { 6 | let plant = Asparagus {}; 7 | println! ("I'm growing {:?}!", plant); 8 | } 9 | -------------------------------------------------------------------------------- /projects/ownership_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let reference_to_nothing = dangle(); 3 | } 4 | 5 | fn dangle() -> &String { 6 | let s = String::from("hello"); 7 | 8 | &s 9 | } 10 | -------------------------------------------------------------------------------- /projects/enum_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let config_max: Option = Some(3u8); 3 | 4 | if let Option::Some(max) = (config_max) { 5 | println! ("极大值被设置为了 {}", max); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/for_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let v = vec! ['a', 'b', 'c']; 3 | 4 | for (index, value) in v.iter().enumerate() { 5 | println! ("{} 处于索引 {} 处", value, index); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/cargo_features_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use art::mix; 2 | use art::PrimaryColor; 3 | 4 | fn main() { 5 | let red = PrimaryColor::Red; 6 | let yellow = PrimaryColor::Yellow; 7 | mix(red, yellow); 8 | } 9 | -------------------------------------------------------------------------------- /projects/data_types/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let c = 'z'; 3 | let z: char = 'ℤ'; // 带有显式的类型注解 4 | let heart_eyed_cat = '😻'; 5 | 6 | println! ("c 为 {c}, z 为 {z}, 爱心猫{heart_eyed_cat}"); 7 | } 8 | -------------------------------------------------------------------------------- /projects/fn_pattn_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn print_coordinates(&(x, y): &(i32, i32)) { 2 | println!("当前坐标:({}, {})", x, y); 3 | } 4 | 5 | fn main() { 6 | let point = (3, -5); 7 | print_coordinates(&point); 8 | } 9 | -------------------------------------------------------------------------------- /projects/art/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "art" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/dst/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dst" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/adder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "adder" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/hello/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/loops/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "loops" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/slices/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "slices" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /src/Ch01_Getting_Started.md: -------------------------------------------------------------------------------- 1 | # 入门 2 | 3 | 现在就开始 Rust 之旅!有很多要掌握的东西,不过千里之行,始于足下。本章将讨论: 4 | 5 | - 在 Linux、macOS 及 Windows 上安装 Rust; 6 | 7 | - 编写一个打印出 `Hello, world!` 的程序; 8 | 9 | - 使用 Rust 的包管理器与构建系统 Cargo 。 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Ch04_Understanding_Ownership.md: -------------------------------------------------------------------------------- 1 | # 掌握所有权 2 | 3 | **Understanding Ownership** 4 | 5 | 所有权是 Rust 最独特的特性,对语言的其他部分有着深刻的影响。他使 Rust 可以在不需要垃圾回收器的情况下,保证内存安全,因此了解所有权的工作原理非常重要。在本章中,我们将讨论所有权,以及几个相关特性:借用、切片,与 Rust 如何将数据放置于内存中。 6 | 7 | 8 | -------------------------------------------------------------------------------- /projects/art/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # art 2 | //! 3 | //! 建模诸多美术概念的一个库。 4 | 5 | pub mod kinds; 6 | pub mod utils; 7 | 8 | pub use self::kinds::PrimaryColor; 9 | pub use self::kinds::SecondaryColor; 10 | pub use self::utils::mix; 11 | -------------------------------------------------------------------------------- /projects/backyard/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "backyard" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/box_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "box_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/branches/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "branches" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/derive_macro_comsumer/src/main.rs: -------------------------------------------------------------------------------- 1 | use hello_macro::HelloMacro; 2 | use hello_macro_derive::HelloMacro; 3 | 4 | #[derive(HelloMacro)] 5 | struct Pancakes; 6 | 7 | fn main() { 8 | Pancakes::hello_macro(); 9 | } 10 | -------------------------------------------------------------------------------- /projects/for_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "for_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/mp_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mp_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/newtype/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "newtype" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/panic_or_not/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::net::IpAddr; 2 | 3 | fn main () { 4 | let home: IpAddr = "127.0.0.1" 5 | .parse() 6 | .expect("硬编码的 IP 地址应是有效的"); 7 | 8 | println! ("{:?}", home); 9 | } 10 | -------------------------------------------------------------------------------- /projects/rc_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rc_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/sp_demos/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sp_demos" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/vec_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vec_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/FnMut_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "FnMut_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/add/add_two/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "add_two" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/aggregator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "aggregator" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/assert_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "assert_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/clippy_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "clippy_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/concur_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "concur_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/data_types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "data_types" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/enum_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "enum_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/extern_code/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "extern_code" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/fah_to_cels/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fah_to_cels" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/functions/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "functions" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/hello_cargo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_cargo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/hello_macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_macro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/hello_world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_world" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/if_let_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "if_let_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/loop_label/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "loop_label" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/match_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "match_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/mutex_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mutex_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/my-project/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "my-project" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/never_type/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "never_type" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/option_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "option_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/rectangles/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rectangles" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/restaurant/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "restaurant" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/simple_blog/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simple_blog" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/simple_gui/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simple_gui" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/string_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "string_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/supertrait/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "supertrait" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/tree_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tree_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/tuple_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tuple_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/variables/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "variables" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/closure_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "closure_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/error_handling_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main () { 2 | use std::net::IpAddr; 3 | 4 | let home: IpAddr = "192.168.0.255" 5 | .parse() 6 | .expect("硬编码的 IP 地址应是有效的"); 7 | 8 | println! ("{}", home); 9 | } 10 | -------------------------------------------------------------------------------- /projects/fn_pattn_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fn_pattn_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/func_pointer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "func_pointer" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/generics_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "generics_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/hashmap_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hashmap_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/iterator_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "iterator_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/limit_tracker/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "limit_tracker" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/raw_pointers/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "raw_pointers" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/rustfix_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustfix_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/string_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let s = "नमस्ते"; 3 | 4 | for c in s.chars() { 5 | println! ("{}", c); 6 | } 7 | 8 | for b in s.bytes() { 9 | println! ("{}", b); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /projects/structs_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "structs_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/type_aliases/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "type_aliases" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/unsafe_trait/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "unsafe_trait" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /append_end.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | PWD="$(pwd)" 3 | for f in $(find "src/" -type f -name "*.md" ); do 4 | if [[ "${f}" == *"SUMMARY"* ]] || [[ "${f}" == *"README"* ]]; then continue; fi 5 | echo -e "\n\n(End)\n\n" >> "$PWD/$f" 6 | done 7 | -------------------------------------------------------------------------------- /projects/associated_type/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "associated_type" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/closure-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "closure-example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/cons_list_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cons_list_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/disambiguation/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "disambiguation" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/drop_func_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "drop_func_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/drop_trait_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "drop_trait_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/hello/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 你好! 6 | 7 | 8 |

糟糕!

9 |

抱歉,我不明白你要什么。

10 | 11 | 12 | -------------------------------------------------------------------------------- /projects/hello/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 你好! 6 | 7 | 8 |

你好!

9 |

来自 Rust 的问好

10 | 11 | 12 | -------------------------------------------------------------------------------- /projects/lifetimes_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lifetimes_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/neo_simple_blog/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "neo_simple_blog" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/ownership_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ownership_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/raw_idenitifers/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "raw_idenitifers" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/ref_cycle_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ref_cycle_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/references_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "references_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/refutable_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "refutable_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/safe_abstraction/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "safe_abstraction" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/static_variable/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "static_variable" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/unsafe_functions/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "unsafe_functions" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/while_let_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "while_let_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/closure_move_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "closure_move_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/declarative_macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "declarative_macro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/encapsulation_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "encapsulation_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/hello_macro_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_macro_derive" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/returning_closure/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "returning_closure" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/error_handling_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "error_handling_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/lyrics_of_xmas_carol/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lyrics_of_xmas_carol" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/operator_overloading/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "operator_overloading" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/pattern_syntax_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pattern_syntax_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/consuming_adaptor_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "consuming_adaptor_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/references_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut s = String::from("你好"); 3 | 4 | let r1 = &s; 5 | { 6 | let r2 = &mut s; 7 | r2.push_str(",世界"); 8 | } 9 | 10 | println! ("s = {}, r2 = {}", s, r1); 11 | } 12 | -------------------------------------------------------------------------------- /projects/add/add_one/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "add_one" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | rand = "^0.8.4" 10 | -------------------------------------------------------------------------------- /projects/add/adder/src/main.rs: -------------------------------------------------------------------------------- 1 | use add_one::add_one; 2 | use add_two::add_two; 3 | 4 | fn main() { 5 | let num = 10; 6 | println!("你好,世界!\n\t{num} 加 1 为 {},{num} 加 2 为 {}!", 7 | add_one(num), 8 | add_two(num) 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /projects/closure_captures_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "closure_capturing_immutable_ref" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /projects/consuming_adaptor_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let v1 = vec! [1, 2, 3]; 3 | 4 | let v1_iter = v1.iter(); 5 | 6 | let total: i32 = v1_iter.sum(); 7 | 8 | assert_eq! (total, 6); 9 | 10 | println! ("v1: {:?}", v1); 11 | } 12 | -------------------------------------------------------------------------------- /projects/art/src/utils.rs: -------------------------------------------------------------------------------- 1 | use crate::kinds::*; 2 | 3 | /// 结合两种等量的主要颜色,创建出 4 | /// 某种次要颜色。 5 | pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor { 6 | // --跳过代码-- 7 | println! ("c1: {:?}, c2: {:?}", c1, c2); 8 | SecondaryColor::Purple 9 | } 10 | -------------------------------------------------------------------------------- /projects/closure_captures_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut list = vec! [1, 2, 3]; 3 | println! ("在定义闭包前:{:?}", list); 4 | 5 | let mut borrows_mutably = || list.push(7); 6 | 7 | borrows_mutably(); 8 | println! ("在调用闭包后:{:?}", list); 9 | } 10 | -------------------------------------------------------------------------------- /projects/nth_fibonacci/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nth_fibonacci" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | num-format = "0.4.0" 10 | -------------------------------------------------------------------------------- /projects/raw_pointers/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut num = 5; 3 | 4 | let r1 = &num as *const i32; 5 | let r2 = &mut num as *mut i32; 6 | 7 | unsafe { 8 | println! ("r1 为:{}", *r1); 9 | println! ("r2 为:{}", *r2); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /projects/closure_move_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | 3 | fn main() { 4 | let list = vec! [1, 2, 3]; 5 | println! ("在定义闭包之前的:{:?}", list); 6 | 7 | thread::spawn(move || println! ("从线程打印出的:{:?}", list)) 8 | .join() 9 | .unwrap(); 10 | } 11 | -------------------------------------------------------------------------------- /projects/generics_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | enum Option_i32 { 2 | Some(i32), 3 | None, 4 | } 5 | 6 | enum Option_f64 { 7 | Some(f64), 8 | None, 9 | } 10 | 11 | fn main() { 12 | let integer = Option_i32::Some(5); 13 | let float = Option_f64::Some(5.0); 14 | } 15 | -------------------------------------------------------------------------------- /projects/minigrep/poem.txt: -------------------------------------------------------------------------------- 1 | I'm nobody! Who are you? 2 | Are you nobody, too? 3 | Then there's a pair of us - don't tell! 4 | They'd banish us, you know. 5 | 6 | How dreary to be somebody! 7 | How public, like a frog 8 | To tell your name the livelong day 9 | To an admiring bog! 10 | -------------------------------------------------------------------------------- /projects/add/add_one/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn add_one(x: i32) -> i32 { 2 | x + 1 3 | } 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | use super::*; 8 | 9 | #[test] 10 | fn it_works() { 11 | let result = add_one(2); 12 | assert_eq!(result, 3); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /projects/art/src/kinds.rs: -------------------------------------------------------------------------------- 1 | /// RYB 颜色模型下的主要颜色。 2 | #[derive(Debug)] 3 | pub enum PrimaryColor { 4 | Red, 5 | Yellow, 6 | Blue, 7 | } 8 | 9 | /// RYB 颜色模型下的次要颜色。 10 | #[derive(Debug)] 11 | pub enum SecondaryColor { 12 | Orange, 13 | Green, 14 | Purple, 15 | } 16 | -------------------------------------------------------------------------------- /projects/cargo_features_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cargo_features_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | art = { path = "../art" } 10 | -------------------------------------------------------------------------------- /projects/static_variable/src/main.rs: -------------------------------------------------------------------------------- 1 | static mut COUNTER: u32 = 0; 2 | 3 | fn add_to_count(inc: u32) { 4 | unsafe { 5 | COUNTER += inc; 6 | } 7 | } 8 | 9 | fn main() { 10 | add_to_count(3); 11 | 12 | unsafe { 13 | println! ("COUNTER: {}", COUNTER); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /projects/hello_macro_derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn add(left: usize, right: usize) -> usize { 2 | left + right 3 | } 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | use super::*; 8 | 9 | #[test] 10 | fn it_works() { 11 | let result = add(2, 2); 12 | assert_eq!(result, 4); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /projects/safe_abstraction/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(warnings)] 2 | 3 | fn main() { 4 | use std::slice; 5 | 6 | let address = 0x01234usize; 7 | let r = address as *mut i32; 8 | 9 | let values: &[i32] = unsafe { slice::from_raw_parts_mut(r, 10000) }; 10 | 11 | println! ("{:?}", values); 12 | } 13 | -------------------------------------------------------------------------------- /projects/concur_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_variables)] 3 | 4 | use std::thread; 5 | 6 | fn main() { 7 | let v = vec! [1, 2, 3]; 8 | 9 | let handle = thread::spawn(move || { 10 | println! ("这里有个矢量值:{:?}", &v); 11 | }); 12 | 13 | handle.join().unwrap(); 14 | } 15 | -------------------------------------------------------------------------------- /projects/minigrep/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "minigrep" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | 10 | [profile.dev] 11 | opt-level = 1 12 | 13 | [profile.release] 14 | opt-level = 3 15 | -------------------------------------------------------------------------------- /projects/add/adder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "adder" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | add_one = { path = "../add_one" } 10 | add_two = { path = "../add_two" } 11 | rand = "0.8.3" 12 | -------------------------------------------------------------------------------- /projects/hello_macro/hello_macro_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello_macro_derive" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [lib] 8 | proc-macro = true 9 | 10 | [dependencies] 11 | syn = "1.0" 12 | quote = "1.0" 13 | -------------------------------------------------------------------------------- /projects/adder/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn add_two(a: i32) -> i32 { 2 | internal_add(a, 2) 3 | } 4 | 5 | fn internal_add(a: i32, b: i32) -> i32 { 6 | a + b 7 | } 8 | 9 | #[cfg(test)] 10 | mod tests { 11 | use super::*; 12 | 13 | #[test] 14 | fn internal() { 15 | assert_eq! (4, internal_add(2, 2)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /projects/guessing_game/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "guessing_game-xfossdotcom" 3 | license = "MIT" 4 | version = "0.1.1" 5 | description = "一个在其中猜出计算机所选数字的有趣游戏。" 6 | edition = "2021" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | rand = "0.8.5" 12 | -------------------------------------------------------------------------------- /projects/neo_simple_blog/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_variables)] 3 | 4 | use neo_simple_blog::Post; 5 | 6 | fn main() { 7 | let mut post = Post::new(); 8 | 9 | post.add_text("这是一个博客帖子。"); 10 | 11 | let post = post.request_review(); 12 | let post = post.approve(); 13 | 14 | assert_eq! ("这是一个博客帖子。", post.content()); 15 | } 16 | -------------------------------------------------------------------------------- /src/Ch06_Enums_and_Pattern_Matching.md: -------------------------------------------------------------------------------- 1 | # 枚举与模式匹配 2 | 3 | **Enums and Pattern Matching** 4 | 5 | 6 | 在本章中,我们将介绍 *枚举,enumerations*,也称为 *枚举,enums*。枚举允许咱们,通过枚举出其可能的 *变种,variants*,来定义某种类型。首先,我们将定义并使用一个枚举,以展示枚举如何与数据一起,编码意义。接下来,我们将探究一个名为 `Option` 的特别有用的枚举,他表示某个值可以是某物,也可以是无。然后,我们将了解 `match` 表达式中的模式匹配,如何使我们可以轻松地针对枚举的不同值,运行不同代码。最后,我们将介绍 `if let` 结构,怎样成为咱们代码中,处理枚举的另一方便简洁的习惯用法。 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/derive_macro_comsumer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "derive_macro_comsumer" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | hello_macro = { path = "../hello_macro" } 10 | hello_macro_derive = { path = "../hello_macro/hello_macro_derive" } 11 | -------------------------------------------------------------------------------- /projects/extern_code/src/main.rs: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | fn abs(input: i32) -> i32; 3 | fn sqrt(input: f64) -> f64; 4 | } 5 | 6 | 7 | #[no_mangle] 8 | pub extern "C" fn call_from_c() { 9 | println! ("刚从 C 调用了一个 Rust 函数!"); 10 | } 11 | 12 | fn main() { 13 | unsafe { 14 | println! ("C 语言中 -3 的绝对值为:{},3.0 的平方根为:{}", abs(-3), sqrt(3.0)); 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /projects/hashmap_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | fn main() { 4 | let text = "hello world wonderful world"; 5 | 6 | let mut map = HashMap::new(); 7 | 8 | for word in text.split_whitespace() { 9 | let count = map.entry(word).or_insert(0); 10 | *count += 1; 11 | } 12 | 13 | println! ("{:?}", map); 14 | 15 | 16 | } 17 | -------------------------------------------------------------------------------- /projects/newtype/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | struct Wrapper(Vec); 4 | 5 | impl fmt::Display for Wrapper { 6 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 7 | write! (f, "[{}]", self.0.join(", ")) 8 | } 9 | } 10 | fn main() { 11 | let w = Wrapper(vec! [String::from("你好"), String::from("世界")]); 12 | println! ("w = {}", w); 13 | } 14 | -------------------------------------------------------------------------------- /projects/guessing_game/src/guessing_game.rs: -------------------------------------------------------------------------------- 1 | pub struct Guess { 2 | value: i32, 3 | } 4 | 5 | impl Guess { 6 | pub fn new(value: i32) -> Guess { 7 | if value < 1 || value > 100 { 8 | panic!("猜数值必须在 1 与 100 之间,得到了 {value}。"); 9 | } 10 | 11 | Guess { value } 12 | } 13 | 14 | pub fn value(&self) -> i32 { 15 | self.value 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /projects/rc_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | #[derive(Debug)] 4 | enum List { 5 | Cons(i32, Rc), 6 | Nil, 7 | } 8 | 9 | use crate::List::{Cons, Nil}; 10 | 11 | fn main() { 12 | let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil))))); 13 | let b = Cons(3, Rc::clone(&a)); 14 | let c = Cons(4, Rc::clone(&a)); 15 | 16 | println! ("b 为: {:?}\nc 为:{:?}", b, c); 17 | } 18 | -------------------------------------------------------------------------------- /projects/slices/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let a = [1, 2, 3, 4, 5]; 3 | 4 | let slice = &a[1..3]; 5 | 6 | assert_eq! (slice, &[2, 3]); 7 | } 8 | 9 | 10 | fn first_word(s: &String) -> &str { 11 | let bytes = s.as_bytes(); 12 | 13 | for (i, &item) in bytes.iter().enumerate() { 14 | if item == b' ' { 15 | return &s[0..i]; 16 | } 17 | } 18 | 19 | &s[..] 20 | } 21 | -------------------------------------------------------------------------------- /projects/disambiguation/src/main.rs: -------------------------------------------------------------------------------- 1 | trait Animal { 2 | fn baby_name() -> String; 3 | } 4 | 5 | struct Dog; 6 | 7 | impl Dog { 8 | fn baby_name() -> String { 9 | String::from("点点") 10 | } 11 | } 12 | 13 | impl Animal for Dog { 14 | fn baby_name() -> String { 15 | String::from("狗崽") 16 | } 17 | } 18 | 19 | fn main() { 20 | println! ("小狗叫做 {}", ::baby_name()); 21 | } 22 | -------------------------------------------------------------------------------- /projects/improved_guessing_game/src/guessing_game.rs: -------------------------------------------------------------------------------- 1 | pub struct Guess { 2 | value: i32, 3 | } 4 | 5 | impl Guess { 6 | pub fn new(value: i32) -> Guess { 7 | if value < 1 || value > 100 { 8 | panic!("Guess value must be between 1 and 100, got {value}."); 9 | } 10 | 11 | Guess { value } 12 | } 13 | 14 | pub fn value(&self) -> i32 { 15 | self.value 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /projects/simple_blog/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_variables)] 3 | 4 | use simple_blog::Post; 5 | 6 | fn main() { 7 | let mut post = Post::new(); 8 | 9 | post.add_text("今天午饭我吃了沙拉。"); 10 | assert_eq! ("", post.content()); 11 | 12 | post.request_review(); 13 | assert_eq! ("", post.content()); 14 | 15 | post.approve(); 16 | assert_eq! ("今天午饭我吃了沙拉。", post.content()); 17 | } 18 | -------------------------------------------------------------------------------- /projects/cargo_features_demo/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # Cargo 特性示例代码箱 2 | //! 3 | //! `cargo_features_demo` 是令到执行某些确切计算更便利 4 | //! 的一些工具的集合。 5 | //! 6 | 7 | /// 将一加到所给数字。 8 | /// # Examples 9 | /// 10 | /// ``` 11 | /// let arg = 5; 12 | /// let answer = cargo_features_demo::add_one(arg); 13 | /// 14 | /// assert_eq! (7, answer); 15 | /// ``` 16 | pub fn add_one(x: i32) -> i32 { 17 | x + 2 18 | } 19 | 20 | #[cfg(test)] 21 | mod tests; 22 | -------------------------------------------------------------------------------- /src/Ch05_Using_Structs_to_Structure_Related_Data.md: -------------------------------------------------------------------------------- 1 | # 使用结构体结构化相关数据 2 | 3 | **Using Structs to Structure Related Data** 4 | 5 | 结构体,`struct`,或 *structure*,是一种自定义数据类型,允许咱们将多个构成一个有意义的组的相关值,打包在一起并取个名字。如果咱们熟悉某门面向对象的语言,那么一个 `struct` 就像是某个对象的数据属性。在本章中,我们把元组与结构体进行对比,以在咱们已有知识的基础上,说明结构体在何时是更好的数据组织方式。 6 | 7 | 我们将演示如何定义和实例化结构体。我们将讨论如何定义关联函数,尤其是称为 *方法,methods* 的关联函数,以指定出与某个结构体类型相关的行为。结构体和枚举(会在第 6 章中讨论),是在咱们程序域中,创建出新类型,以充分利用 Rust 的编译时类型检查的两个基本构建模块。 8 | 9 | 10 | -------------------------------------------------------------------------------- /projects/type_aliases/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | type Kilometers = i32; 3 | 4 | let x: i32 = 5; 5 | let y: Kilometers = 5; 6 | 7 | assert_eq! (x, y); 8 | 9 | type Thunk = Box; 10 | 11 | let f: Thunk = Box::new(|| println! ("嗨")); 12 | 13 | fn takes_long_type(f: Thunk) { 14 | // --跳过代码-- 15 | } 16 | 17 | fn returns_long_type() -> Thunk { 18 | // --跳过代码-- 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /projects/hello-async/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{thread, time::Duration}; 2 | 3 | fn main() { 4 | let (tx, mut rx) = trpl::channel(); 5 | 6 | thread::spawn(move || { 7 | for i in 1..11 { 8 | tx.send(i).unwrap(); 9 | thread::sleep(Duration::from_secs(1)); 10 | } 11 | }); 12 | 13 | trpl::run(async { 14 | while let Some(message) = rx.recv().await { 15 | println!("{message}"); 16 | } 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /src/404.md: -------------------------------------------------------------------------------- 1 | ### Document not found(404) 2 | 3 | **文档未找到(404)** 4 | 5 | 6 | 抱歉,此 URL 无效。请使用导航栏或搜索继续。将在 n 秒后重定向到主页...... 7 | 8 | 9 | This URL is invalid, sorry. Please use the navigation bar or search to continue. It will be redirected to home in n seconds... 10 | 11 | 12 | (End) 13 | 14 | 15 | -------------------------------------------------------------------------------- /projects/add/add_two/src/lib.rs: -------------------------------------------------------------------------------- 1 | /// 将一个整数加 2。 2 | /// 3 | /// # Examples 4 | /// 5 | /// ``` 6 | /// let num = 15; 7 | /// 8 | /// let answer = add_two::add_two(num); 9 | /// assert_eq! (answer, 17); 10 | /// ``` 11 | /// 12 | pub fn add_two(num: i32) -> i32 { 13 | num + 2 14 | } 15 | 16 | #[cfg(test)] 17 | mod tests { 18 | use super::*; 19 | 20 | #[test] 21 | fn it_works() { 22 | let result = add_two(7); 23 | assert_eq!(result, 9); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Ch17_Object_Oriented_Programming_Features_of_Rust.md: -------------------------------------------------------------------------------- 1 | # Rust 的面向对象编程特性 2 | 3 | **Object Oriented Programming Features of Rust** 4 | 5 | 面向对象编程方法,object-oriented programming, OOP, 是建模程序的一种方法。对象是在 20 世纪 60 年代,在编程语言 Simula 中所引入的一个程序化概念。正是那些对象,影响了 Alan Kay 的编程架构,其中对象会相互传递消息。为描述这种架构,他在 1967 年创造了面向对象编程这个术语。有许多互相竞争的定义,都描述了 OOP 是什么,而根据其中一些定义,Rust 属于面向对象的,但根据另一些,Rust 则不属于面向对象的。在本章中,咱们将探讨通常被看作是面向对象的一些特征,以及这些特征怎样被转译为 Rust 的习惯说法。随后咱们将给出在 Rust 怎样实现面向对象的设计模式,并讨论在这样做,与相反采用 Rust 的一些长处来实现解决方案,之间的权衡取舍。 6 | 7 | 8 | -------------------------------------------------------------------------------- /projects/lifetimes_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | fn longest_with_an_announcement<'a, T>( 4 | x: &'a str, 5 | y: &'a str, 6 | ann: T, 7 | ) -> &'a str 8 | where 9 | T: Display, 10 | { 11 | println! ("通知!{}", ann); 12 | if x.len() > y.len() { 13 | x 14 | } else { 15 | y 16 | } 17 | } 18 | 19 | fn main() { 20 | let result = longest_with_an_announcement("abc", "测试", "计算结果已出来。"); 21 | 22 | println! ("{}", result); 23 | } 24 | -------------------------------------------------------------------------------- /projects/drop_func_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | struct CustomSmartPointer { 2 | data: String, 3 | } 4 | 5 | impl Drop for CustomSmartPointer { 6 | fn drop(&mut self) { 7 | println! ("正在使用数据 `{}` 弃用 CustomSmartPointer!", self.data); 8 | } 9 | } 10 | 11 | fn main() { 12 | let c = CustomSmartPointer { 13 | data: String::from("我的事情"), 14 | }; 15 | 16 | println! ("已创建出一个 CustomSmartPointer 实例。"); 17 | drop(c); 18 | println! ("在 main 结束之前这个 CustomSmartPointer 已被弃用。") 19 | } 20 | -------------------------------------------------------------------------------- /projects/tuple_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | fn main() { 4 | let a = [1, 2, 3, 4, 5]; 5 | 6 | println! ("请输入一个数组索引。"); 7 | 8 | let mut index = String::new(); 9 | 10 | io::stdin() 11 | .read_line(&mut index) 12 | .expect("读取行失败,failed to read line"); 13 | 14 | let index: usize = index 15 | .trim() 16 | .parse() 17 | .expect("输入的所以并非一个数字"); 18 | 19 | let element = a[index]; 20 | 21 | println! ("位于索引 {index} 出的元素值为:{element}"); 22 | } 23 | -------------------------------------------------------------------------------- /projects/box_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Deref; 2 | 3 | struct MyBox(T); 4 | 5 | impl MyBox { 6 | fn new(x: T) -> MyBox { 7 | MyBox(x) 8 | } 9 | } 10 | 11 | impl Deref for MyBox { 12 | type Target = T; 13 | 14 | fn deref(&self) -> &Self::Target { 15 | &self.0 16 | } 17 | } 18 | 19 | fn main() { 20 | let boxed_string = MyBox::new(String::from("装箱的字符串")); 21 | 22 | let x = 5; 23 | let y = &x; 24 | println! ("{}, {}", *boxed_string, *y); 25 | } 26 | -------------------------------------------------------------------------------- /projects/drop_trait_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | struct CustomSmartPointer { 2 | data: String, 3 | } 4 | 5 | impl Drop for CustomSmartPointer { 6 | fn drop(&mut self) { 7 | println! ("正在使用数据 `{}` 弃用 CustomSmartPointer!", self.data); 8 | } 9 | } 10 | 11 | fn main() { 12 | let c = CustomSmartPointer { 13 | data: String::from("c - 我的事情"), 14 | }; 15 | let d = CustomSmartPointer { 16 | data: String::from("d - 其他事情"), 17 | }; 18 | println! ("已创建出一些 CustomSmartPointer 实例"); 19 | } 20 | -------------------------------------------------------------------------------- /projects/minigrep/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::process; 3 | 4 | use minigrep::data_structures::Config; 5 | 6 | fn main() { 7 | let config = Config::build(env::args()) 8 | .unwrap_or_else(|err| { 9 | eprintln! ("解析参数时遇到问题:{err}"); 10 | process::exit(1); 11 | }); 12 | 13 | println! ("在文件 {} 中检索:{}", config.file_path, config.query); 14 | 15 | if let Err(e) = minigrep::run(config) { 16 | eprintln! ("应用程序错误:{e}"); 17 | process::exit(1); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Ch03_Common_Programming_Concepts.md: -------------------------------------------------------------------------------- 1 | # 常见编程概念 2 | 3 | **Common Programming Concepts** 4 | 5 | 6 | 本章介绍几乎所有编程语言中都会出现的概念,以及它们在 Rust 中的工作原理。许多编程语言,在其核心都有许多共同点。本章介绍的概念都不是 Rust 所独有的,但我们会在 Rust 的上下文中讨论这些概念,并解释使用这些概念的惯例。 7 | 8 | 具体来说,咱们将了解变量、基本类型、函数、注释和控制流等。每个 Rust 程序中,都会有这些基础知识,及早掌握他们,将为咱们的起步打下坚实的基础。 9 | 10 | > **关键字,keywords** 11 | > 12 | > 与其他语言一样,Rust 语言也有一套仅供这门语言使用的 *关键字,keywords*。请记住,咱们不能将这些关键字,用作变量或函数的名字。大多数关键字,都有特殊含义,而咱们将在咱们的 Rust 程序中,使用他们完成各种任务;少数关键字目前没有与其相关的功能,但已被保留用于将来可能添加到 Rust 中的功能。咱们可以在 [附录 A](appendix/keywords.md) 中,找到这些关键字的列表。 13 | 14 | 15 | -------------------------------------------------------------------------------- /projects/loop_label/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let mut count = 0; 3 | 4 | 'counting_up: loop { 5 | println! ("count = {count}"); 6 | let mut remaining = 10; 7 | 8 | loop { 9 | println! ("remaining = {remaining}"); 10 | if remaining == 9 { 11 | break; 12 | } 13 | 14 | if count == 2 { 15 | break 'counting_up; 16 | } 17 | remaining -= 1; 18 | } 19 | 20 | count += 1; 21 | } 22 | 23 | println! ("End count = {count}"); 24 | } 25 | -------------------------------------------------------------------------------- /src/Ch14_More_about_Cargo_and_Crates-io.md: -------------------------------------------------------------------------------- 1 | # Cargo 的其他方面与 Crates.io 2 | 3 | **More About Cargo and Crates.io** 4 | 5 | 到目前为止,咱们只使用了 Cargo 的一些最基本特性,来构建、运行与测试所编写的代码,而 Cargo 可以完成多得多的事情。本章中,咱们将讨论他一些别的、更为先进的特性,来展示如何完成以下的这些事情: 6 | 7 | - 经由不同发布配置文件,定制咱们的构建,customize your build through release profiles; 8 | - 把库发布在 [crates.io](https://crates.io) 上; 9 | - 使用工作区来组织大型项目,organize large projects with workspaces; 10 | - 从 [crates.io](https://crates.io) 安装库; 11 | - 使用定制命令来扩展 Cargo 。 12 | 13 | 14 | 相比咱们在本章会讲到的功能,Cargo 甚至能完成更多,因此对于 Cargo 全部特性的完整阐释,请参阅 [他的文档](https://doc.rust-lang.org/cargo/)。 15 | 16 | 17 | -------------------------------------------------------------------------------- /projects/FnMut_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Rectangle { 3 | width: u32, 4 | height: u32, 5 | } 6 | 7 | fn main() { 8 | let mut list = [ 9 | Rectangle { width: 10, height: 1 }, 10 | Rectangle { width: 3, height: 5 }, 11 | Rectangle { width: 7, height: 12 }, 12 | ]; 13 | 14 | let mut sort_operations = vec! []; 15 | let value = String::from("按照被调用到的 key"); 16 | 17 | list.sort_by_key(|r| { 18 | sort_operations.push(&value); 19 | r.width 20 | }); 21 | println! ("{:#?}\n{:#?}", list, sort_operations); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /projects/closure-example/src/main.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Rectangle { 3 | width: u32, 4 | height: u32, 5 | } 6 | 7 | fn main() { 8 | let mut list = [ 9 | Rectangle { width: 10, height: 1 }, 10 | Rectangle { width: 3, height: 5 }, 11 | Rectangle { width: 7, height: 12 }, 12 | ]; 13 | 14 | let mut sort_operations = vec! []; 15 | let value = String::from("按照被调用到的 key"); 16 | 17 | list.sort_by_key(|r| { 18 | sort_operations.push(&value); 19 | r.width 20 | }); 21 | println! ("{:#?}\n{:#?}", list, sort_operations); 22 | } 23 | -------------------------------------------------------------------------------- /src/crates-io/custom_commands.md: -------------------------------------------------------------------------------- 1 | # 使用定制命令扩展 Cargo 2 | 3 | **Extending Cargo with Custom Commands** 4 | 5 | Cargo 被设计为在无需修改 Cargo 下,咱们就可以使用新的子命令,对其加以扩展。若咱们的 `$PATH` 中有名为 `cargo-something` 的二进制程序,咱们便可通过运行 `cargo something`,将其作为 Cargo 的子命令运行。像这样的定制命令,还会在咱们运行 `cargo --list` 时给列出来。使用 `cargo install` 安装扩展,并随后跟运行内建的 Cargo 工具一样运行他们的这种能力,正是 Cargo 设计的一项超级便利的好处! 6 | 7 | 8 | # 本章小结 9 | 10 | 运用 Cargo 与 [crates.io](https://crates.io) 分享代码,是令到 Rust 生态对于许多不同任务都有用的一个方面。Rust 的标准库是小型且稳定的,但在不同于语言本身的时间线上,代码箱则易于共享、运用以及改进。请不要羞于在 [crates.io](https://crates.io) 上分享对自己有用的代码;那些代码或许对其他人也同样有用! 11 | 12 | 13 | (End) 14 | 15 | 16 | -------------------------------------------------------------------------------- /projects/minigrep/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | #[test] 4 | fn case_sensitive() { 5 | let query = "duct"; 6 | let contents = "\ 7 | Rust: 8 | safe, fast, productive. 9 | Pick three. 10 | Duct tape."; 11 | 12 | assert_eq! (vec! ["safe, fast, productive."], search(query, contents)); 13 | } 14 | 15 | #[test] 16 | fn case_insensitive() { 17 | let query = "rUst"; 18 | let contents = "\ 19 | Rust: 20 | safe, fast, productive. 21 | Pick three. 22 | Trust me."; 23 | 24 | assert_eq! ( 25 | vec! ["Rust:", "Trust me."], 26 | search_insensitive(query, contents) 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /src/Ch08_Common_Collections.md: -------------------------------------------------------------------------------- 1 | # 一些常用的集合 2 | 3 | **Common Collections** 4 | 5 | Rust 标准库中包含了几种名为 *集合(collections)* 的有用数据结构。大多数其他数据类型,都表示某个特定值,而集合则可包含多个值。与内建的数组和元组类型不同,这些集合所指向的数据,是存储在堆上的,这就意味着在编译时不需要知道数据的数量,进而在程序运行时,这些数据数量可增加或减少。每种集合都有不同能力与开销,针对应用程序当下情况,而选择恰当的一种集合,则是随着时间推移,要发展的一项编程技能。本章中,将讨论在 Rust 程序中,经常被用到的三种集合: 6 | 7 | - *矢量* 允许存储并列的数个值; 8 | - *字符串* 是一些字符的集合。早先曾提到过 `String` 类型,而本章就要深入讨论到他; 9 | - *哈希映射(hash map)* 允许将某个值与特定键进行关联。他是一种更为通用数据结构、名为 *映射(map)* 的一个特定实现。 10 | 11 | 要了解由标准库所提供的其他类别集合,请参阅 [文档](https://doc.rust-lang.org/std/collections/index.html)。 12 | 13 | 这里将讨论怎样创建与更新矢量、字符串与哈希映射,同时会讨论他们因何而变得特殊。 14 | 15 | 16 | -------------------------------------------------------------------------------- /projects/simple_gui/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_variables)] 3 | 4 | use simple_gui::Draw; 5 | 6 | pub struct SelectBox { 7 | width: u32, 8 | height: u32, 9 | options: Vec, 10 | } 11 | 12 | impl Draw for SelectBox { 13 | fn draw(&self) { 14 | // 具体绘制复选框的代码 15 | println! ("这是一个大小为:{} 像素 x {} 像素,有着选项:{:?} 的复选框;", self.width, self.height, self.options); 16 | } 17 | } 18 | 19 | use simple_gui::Screen; 20 | 21 | pub fn main() { 22 | let screen = Screen { 23 | components: vec! [Box::new(String::from("你好"))], 24 | }; 25 | 26 | screen.run(); 27 | } 28 | -------------------------------------------------------------------------------- /projects/if_let_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_variables)] 3 | 4 | fn main() { 5 | let favorite_color: Option<&str> = None; 6 | let is_tuesday = false; 7 | let age: Result = "34".parse(); 8 | 9 | if let Some(color) = favorite_color { 10 | println! ("使用你喜欢的颜色,{color},作为背景"); 11 | } else if is_tuesday { 12 | println! ("周二是绿色的一天!"); 13 | } else if let Ok(age) = age { 14 | if age > 30 { 15 | println! ("使用紫色作为背景色"); 16 | } else { 17 | println! ("使用橙色作为背景色"); 18 | } 19 | } else { 20 | println! ("使用蓝色作为背景色"); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Ch09_Error_Handling.md: -------------------------------------------------------------------------------- 1 | # 错误处理 2 | 3 | 错误属于软件中的家常便饭,因此 Rust 提供了数种用于处理出错情形的特性。许多情况下,Rust 要求咱们在咱们代码编译前,知晓某个错误的可能性并采取一些措施。通过确保咱们在将代码部署到生产环境前,发现错误并进行适当处理,这一要求令到咱们的程序更加健壮! 4 | 5 | 6 | Rust 将错误分为两大类: 7 | 8 | - *可恢复* 错误,*recoverable* errors; 9 | - 与 *不可恢复* 错误, *unrecoverable* errors。 10 | 11 | 12 | 对于比如 *文件未找到* 这样的可恢复错误,我们很可能只想将此问题报告给用户并重试该操作。而比如试图访问超出某个数组末尾位置这种不可恢复错误,则总是一些代码问题,bugs,的表征,因此我们会打算立即停止程序。 13 | 14 | 15 | 大多数语言并不区分这两类错误,而是使用异常等机制,以同样方式处理这两种错误。**Rust 没有异常**。相反,他有着 16 | 17 | - 用于可恢复错误的类型 `Result`; 18 | - 和在程序发生不可恢复错误时,停止执行的 `panic!` 宏。 19 | 20 | 21 | 本章首先介绍 `panic!` 宏的调用,然后讨论返回 `Result` 的值。此外,我们将探讨在决定是尝试从错误中恢复,还是停止执行时的一些考量。 22 | 23 | 24 | -------------------------------------------------------------------------------- /projects/structs_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | struct User { 2 | active: bool, 3 | username: String, 4 | email: String, 5 | sign_in_count: u64, 6 | } 7 | 8 | impl Rectangle { 9 | fn area(&self) -> u32 { 10 | self.width * self.height 11 | } 12 | } 13 | 14 | fn main() { 15 | let user1 = User { 16 | active: true, 17 | username: String::from("someusername123"), 18 | email: String::from("someone@example.com"), 19 | sign_in_count: 1, 20 | }; 21 | 22 | 23 | let user2 = User { 24 | email: String::from("another@example.com"), 25 | ..user1 26 | }; 27 | 28 | println! ("{}", user2.email); 29 | } 30 | -------------------------------------------------------------------------------- /projects/restaurant/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod back_of_house { 2 | pub enum Appetizer { 3 | Soup, 4 | Salad, 5 | } 6 | 7 | pub struct Breakfast { 8 | pub toast: String, 9 | seasonal_fruit: String, 10 | } 11 | 12 | impl Breakfast { 13 | pub fn summer(toast: &str) -> Breakfast { 14 | Breakfast { 15 | toast: String::from(toast), 16 | seasonal_fruit: String::from("peaches"), 17 | } 18 | } 19 | } 20 | } 21 | 22 | mod front_of_house; 23 | 24 | pub use crate::front_of_house::hosting; 25 | 26 | pub fn eat_at_restaurant() { 27 | hosting::add_to_waitlist(); 28 | } 29 | -------------------------------------------------------------------------------- /projects/mutex_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_variables)] 3 | 4 | use std::sync::{Arc, Mutex}; 5 | use std::thread; 6 | 7 | fn main() { 8 | let counter = Arc::new(Mutex::new(0)); 9 | let mut handles = vec! []; 10 | 11 | for _ in 0..10 { 12 | let counter = Arc::clone(&counter); 13 | let handle = thread::spawn(move || { 14 | let mut num = counter.lock().unwrap(); 15 | 16 | *num += 1; 17 | }); 18 | 19 | handles.push(handle); 20 | } 21 | 22 | for handle in handles { 23 | handle.join().unwrap(); 24 | } 25 | 26 | println! ("结果为:{}", *counter.lock().unwrap()); 27 | } 28 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Lenny Peng"] 3 | language = "zh" 4 | src = "src" 5 | title = "Yet another Chinese rust-lang book." 6 | description = "又一本 rust-lang 书,Yet another Chinese rust-lang book。" 7 | 8 | [preprocessor.last-changed] 9 | command = "mdbook-last-changed" 10 | renderer = ["html"] 11 | 12 | 13 | [preprocessor.pagetoc] 14 | [output.html] 15 | additional-css = ["theme/pagetoc.css"] 16 | additional-js = ["theme/pagetoc.js"] 17 | git-repository-url = "https://github.com/gnu4cn/rust-lang-zh_CN" 18 | git-repository-icon = "fa-github" 19 | 20 | [output.html.print] 21 | enable = false 22 | 23 | [output.html.search] 24 | enable = false 25 | 26 | [output.html.favicon] 27 | png = true 28 | -------------------------------------------------------------------------------- /projects/simple_gui/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_variables)] 3 | 4 | pub trait Draw { 5 | fn draw(&self); 6 | } 7 | 8 | pub struct Screen { 9 | pub components: Vec>, 10 | } 11 | 12 | impl Screen { 13 | pub fn run(&self) { 14 | for component in self.components.iter() { 15 | component.draw(); 16 | } 17 | } 18 | } 19 | 20 | pub struct Button { 21 | pub width: u32, 22 | pub height: u32, 23 | pub label: String, 24 | } 25 | 26 | impl Draw for Button { 27 | fn draw(&self) { 28 | // 具体绘制按钮的代码 29 | println! ("这是一个大小:{} 像素 x {} 像素,有着 “{}” 标签的按钮;", self.width, self.height, self.label); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/images/circled-cc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /projects/traits_demo/src/aggregator/lib.rs: -------------------------------------------------------------------------------- 1 | pub trait Summary { 2 | fn summarize(&self) -> String; 3 | } 4 | 5 | pub struct NewsArticle { 6 | pub headline: String, 7 | pub location: String, 8 | pub author: String, 9 | pub content: String, 10 | } 11 | 12 | impl Summary for NewsArticle { 13 | fn summarize(&self) -> String { 14 | format!("{}, by {} ({})", self.headline, self.author, self.location) 15 | } 16 | } 17 | 18 | pub struct Tweet { 19 | pub username: String, 20 | pub content: String, 21 | pub reply: bool, 22 | pub retweet: bool, 23 | } 24 | 25 | impl Summary for Tweet { 26 | fn summarize(&self) -> String { 27 | format!("{}: {}", self.username, self.content) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /projects/pattern_syntax_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | enum Message { 3 | Hello { id: u32 }, 4 | } 5 | 6 | let msg = Message::Hello { id: 5 }; 7 | 8 | match msg { 9 | Message::Hello { 10 | id: id_variable @ 3..=7, 11 | } => println! ("找到位于范围内的一个 id: {}", id_variable), 12 | Message::Hello { id: 10..=12 } => { 13 | println! ("找到位于另一范围的一个 id"); 14 | }, 15 | Message::Hello { id } => println! ("找到别的一个 id: {}", id), 16 | } 17 | 18 | let level = 0.8; 19 | 20 | match level { 21 | l if l >= 1.0 => println! ("超出额度"), 22 | l if l >= 0.9 => println! ("超出 90% 额度"), 23 | l if l >= 0.75 => println! ("超出 75% 额度"), 24 | _ => (), 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /projects/cons_list_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | enum List { 3 | Cons(Rc>, Rc), 4 | Nil, 5 | } 6 | 7 | use crate::List::{Cons, Nil}; 8 | use std::cell::RefCell; 9 | use std::rc::Rc; 10 | 11 | fn main() { 12 | let value = Rc::new(RefCell::new(5)); 13 | 14 | let a = Rc::new( 15 | Cons( 16 | Rc::clone(&value), 17 | Rc::new(Nil) 18 | ) 19 | ); 20 | 21 | let b = Cons( 22 | Rc::new(RefCell::new(3)), 23 | Rc::clone(&a) 24 | ); 25 | let c = Cons( 26 | Rc::new(RefCell::new(4)), 27 | Rc::clone(&a) 28 | ); 29 | 30 | *value.borrow_mut() += 10; 31 | 32 | println! ("之后的 a = {:?}", a); 33 | println! ("之后的 b = {:?}", b); 34 | println! ("之后的 c = {:?}", c); 35 | } 36 | -------------------------------------------------------------------------------- /projects/hello_macro/hello_macro_derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | use quote::quote; 3 | use syn; 4 | 5 | #[proc_macro_derive(HelloMacro)] 6 | pub fn hello_macro_derive(input: TokenStream) -> TokenStream { 7 | // 以语法树形式,构建出咱们可操作 Rust 代码的表示 8 | // Construct a representation of Rust code as a syntax tree 9 | // that we can manipulate 10 | let ast = syn::parse(input).unwrap(); 11 | 12 | // 构造出这个特质实现 13 | impl_hello_macro(&ast) 14 | } 15 | 16 | fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream { 17 | let name = &ast.ident; 18 | let gen = quote! { 19 | impl HelloMacro for #name { 20 | fn hello_macro() { 21 | println! ("你好,宏!我的名字叫 {}!", stringify! (#name)); 22 | } 23 | } 24 | }; 25 | gen.into() 26 | } 27 | -------------------------------------------------------------------------------- /projects/func_pointer/src/main.rs: -------------------------------------------------------------------------------- 1 | fn add_one(x: i32) -> i32 { 2 | x + 1 3 | } 4 | 5 | fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 { 6 | f(arg) + f(arg) 7 | } 8 | 9 | 10 | fn main() { 11 | let answer = do_twice(add_one, 5); 12 | 13 | println! ("答案为:{}", answer); 14 | 15 | let list_of_numbers = vec! [1, 2, 3]; 16 | let list_of_strings: Vec = 17 | list_of_numbers.iter().map(ToString::to_string).collect(); 18 | 19 | println! ("结果为:{:?}", list_of_strings); 20 | 21 | #[derive(Debug)] 22 | enum Status { 23 | Value(u32), 24 | Stop, 25 | } 26 | 27 | let mut list_of_statuses: Vec = (0u32..20).map(Status::Value).collect(); 28 | list_of_statuses.append(&mut vec! [Status::Stop]); 29 | println! ("list_of_statuses: {:?}", list_of_statuses); 30 | } 31 | -------------------------------------------------------------------------------- /projects/iterator_demo/src/tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | #[test] 4 | fn filter_by_size() { 5 | let shoes = vec! [ 6 | Shoe { 7 | size: 10, 8 | style: String::from("sneaker"), 9 | }, 10 | Shoe { 11 | size: 13, 12 | style: String::from("sandal"), 13 | }, 14 | Shoe { 15 | size: 10, 16 | style: String::from("boot"), 17 | }, 18 | ]; 19 | 20 | let in_my_size = shoes_in_size(shoes, 10); 21 | 22 | assert_eq! ( 23 | in_my_size, 24 | vec! [ 25 | Shoe { 26 | size: 10, 27 | style: String::from("sneaker"), 28 | }, 29 | Shoe { 30 | size: 10, 31 | style: String::from("boot"), 32 | }, 33 | ] 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /projects/iterator_demo/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[derive(PartialEq, Debug)] 2 | struct Shoe { 3 | size: u32, 4 | style: String, 5 | } 6 | 7 | fn shoes_in_size(shoes: Vec, shoe_size: u32) -> Vec { 8 | shoes.into_iter().filter(|s| s.size == shoe_size).collect() 9 | } 10 | 11 | #[cfg(test)] 12 | mod tests; 13 | 14 | #[test] 15 | fn iterator_demonstration() { 16 | let v1 = vec! [1, 2, 3]; 17 | 18 | let mut v1_iter = v1.iter(); 19 | 20 | assert_eq! (v1_iter.next(), Some(&1)); 21 | assert_eq! (v1_iter.next(), Some(&2)); 22 | assert_eq! (v1_iter.next(), Some(&3)); 23 | assert_eq! (v1_iter.next(), None); 24 | } 25 | 26 | #[test] 27 | fn iterator_sum() { 28 | let v1 = vec! [1, 2, 3]; 29 | 30 | let v1_iter = v1.iter(); 31 | 32 | let total: i32 = v1_iter.sum(); 33 | 34 | assert_eq! (total, 6); 35 | } 36 | -------------------------------------------------------------------------------- /projects/supertrait/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | trait OutlinePrint: fmt::Display { 4 | fn outline_print(&self) { 5 | let output = self.to_string(); 6 | let len = output.len(); 7 | 8 | println! ("{}", "*".repeat(len + 4)); 9 | println! ("*{}*", " ".repeat(len + 2)); 10 | println! ("* {} *", output); 11 | println! ("*{}*", " ".repeat(len + 2)); 12 | println! ("{}", "*".repeat(len + 4)); 13 | } 14 | } 15 | 16 | struct Point { 17 | x: i32, 18 | y: i32, 19 | } 20 | 21 | impl fmt::Display for Point { 22 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 23 | write! (f, "({}, {})", self.x, self.y) 24 | } 25 | } 26 | 27 | impl OutlinePrint for Point {} 28 | 29 | fn main() { 30 | let p = Point { x: -2, y: 3 }; 31 | p.outline_print(); 32 | } 33 | -------------------------------------------------------------------------------- /src/Ch13_Functional_Language_Features_Iterators_and_Closures.md: -------------------------------------------------------------------------------- 1 | # 函数式编程语言特性:迭代器与闭包 2 | 3 | Rust 的设计曾受到许多现有的语言和技术的启发,而一个显著的影响,便是 *函数式编程,functional programming*。以函数式风格编程,通常包括了通过把函数传入到参数中,或从其他函数返回函数,及将函数赋值给变量以便稍后执行等等,而将函数当作值使用,programming in a functional style often includes using functions as values by using functions as values by passing them in arguments, returning them from another functions, assigning them to variables for later execution, and so forth。 4 | 5 | 本章中,咱们不会讨论函数式编程是什么或不是什么的问题,而将讨论与许多通常被指为函数式编程语言中特性类似的 Rust 特性。 6 | 7 | 更具体地说,咱们将讲到: 8 | 9 | - *闭包,closures*,可存储在变量中、类似函数的结构体; 10 | - *迭代器,iterators*,处理元素序列的方式,a way of processing a series of elements; 11 | - 如何使用闭包与迭代器,来改进第 12 章中的那个 I/O 项目; 12 | - 闭包与迭代器的性能问题(剧透警告:他们比咱们可能想的要快!)。 13 | 14 | 咱们已经讲到过其他的一些 Rust 特性,诸如模式匹配与枚举等,也是受函数式编程影响的。由于掌握闭包与迭代器,是编写惯用、快速 Rust 代码的重要方面,因此咱们将把这整章,都用来讲解他们。 15 | 16 | 17 | -------------------------------------------------------------------------------- /projects/minigrep/src/data_structures.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | pub struct Config { 4 | pub query: String, 5 | pub file_path: String, 6 | pub ignore_case: bool, 7 | } 8 | 9 | impl Config { 10 | pub fn build( 11 | mut args: impl Iterator, 12 | ) -> Result { 13 | args.next(); 14 | 15 | let query = match args.next() { 16 | Some(arg) => arg, 17 | None => return Err("未曾获取到查询字串"), 18 | }; 19 | 20 | let file_path = match args.next() { 21 | Some(arg) => arg, 22 | None => return Err("未曾获取到文件路径"), 23 | }; 24 | 25 | let ignore_case = env::var("IGNORE_CASE").is_ok(); 26 | 27 | Ok(Config { 28 | query, 29 | file_path, 30 | ignore_case, 31 | }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Ch18_Patterns_and_Matching.md: -------------------------------------------------------------------------------- 1 | # 模式与匹配 2 | 3 | **Patterns and Matching** 4 | 5 | *模式,patterns* 属于 Rust 中,用于与不论简单,还是复杂的类型结构体,做匹配的一种特别语法。与 `match` 表达式及其他一些构件,other constructs,结合使用模式,就会给到咱们对程序控制流程更多的掌控。模式有以下元素的一些组合构成: 6 | 7 | - 字面值 8 | 9 | - 解构过后的数组、枚举、结构体或元组等,destructured arrays, enums, structs, or tuples 10 | 11 | - 变量 12 | 13 | - 通配符,wildcards 14 | 15 | - 占位符,placeholders 16 | 17 | 18 | 一些示例模式,包括 `x`、`(a, 3)` 及 `Some(Color::Red)` 等。在模式为有效的语境中,这些组件描述了数据的形状,the shape of data。咱们的程序随后就会将一些值,与这些模式做匹配,来判断其是否有着数据的正确形状,而继续运行代码的某个特定片段。 19 | 20 | 21 | 要运用某个模式,咱们就要将其与某个值比较。在该模式与那个值匹配时,咱们在咱们的代码中,使用这个值的那些部分。回顾第 6 章中用到模式的那些 `match` 表达式,比如那个硬币分类机器示例。在值满足模式形状时,咱们就可以使用那些命名的代码片段。而在不满足时,与该模式关系的代码就不会运行。 22 | 23 | 本章时与模式相关全部内容的一个参考。咱们将涵盖运用模式的那些有效位置、可证伪与不可证伪模式的区别,the difference between refutable and irrefutable patterns,以及可能见到的那些不同类别的模式语法。在本章最后,咱们将获悉,如何运用模式来清晰地表达许多概念。 24 | 25 | 26 | -------------------------------------------------------------------------------- /projects/assert_demo/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn add_two(a: i32) -> i32 { 2 | a + 2 3 | } 4 | 5 | pub fn nth_fibonacci(n: u64) -> u64 { 6 | 7 | if n == 0 || n == 1 { 8 | return n; 9 | } else { 10 | return nth_fibonacci(n - 1) + nth_fibonacci(n - 2); 11 | } 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use super::*; 17 | 18 | #[test] 19 | fn add_two_and_two() { 20 | assert_eq! (4, add_two(2)); 21 | } 22 | 23 | #[test] 24 | fn add_three_and_two() { 25 | assert_eq! (5, add_two(3)); 26 | } 27 | 28 | #[test] 29 | fn one_hundred() { 30 | assert_eq! (102, add_two(100)); 31 | } 32 | 33 | #[test] 34 | fn it_works() { 35 | assert_eq! (2 + 2, 4); 36 | } 37 | 38 | #[test] 39 | #[ignore] 40 | fn expensive_test() { 41 | assert_ne! (100, nth_fibonacci(50)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /projects/io_project/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | use super::*; 4 | 5 | #[test] 6 | fn one_result() { 7 | let query = "duct"; 8 | let contents = "\ 9 | Rust: 10 | safe, fast, productive. 11 | Pick three."; 12 | 13 | assert_eq! (vec! ["safe, fast, productive."], search(query, contents)); 14 | } 15 | } 16 | 17 | 18 | pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { 19 | let mut results = Vec::new(); 20 | 21 | for line in contents.lines() { 22 | if line.contains(query) { 23 | results.push(line); 24 | } 25 | } 26 | 27 | results 28 | } 29 | 30 | pub fn run(config: Config) -> Result<(), Box>{ 31 | let contents = fs::read_to_string(config.file_path)?; 32 | 33 | for line in search(&config.query, &contents) { 34 | println! ("{line}"); 35 | } 36 | 37 | Ok(()) 38 | } 39 | -------------------------------------------------------------------------------- /src/Ch20_Final_Project_Building_a_Multithreaded_Web_Server.md: -------------------------------------------------------------------------------- 1 | # 最后项目:构建一个多线程的 Web 服务器 2 | 3 | **Final Project: Building a Multithreaded Web Server** 4 | 5 | 6 | 这是一个漫长的旅程,但我们已经到达了本书的结尾。在本章中,咱们将一起构建又一个项目,来演示咱们在最后这些章中,曾涉及到的一些概念,同时回顾一些较早的内容。 7 | 8 | 对于这个最后的项目,咱们将构造一个讲出 “你好”,且在浏览器中看起来如图 20-1 那样的一个 web 浏览器。 9 | 10 | 11 | ![咱们最后一起做的项目](images/20-01.png) 12 | 13 | *图 20-1:咱们最后一起做的项目* 14 | 15 | 以下是构建这个 web 服务器的计划: 16 | 17 | 1. 学习一点有关 TCP 与 HTTP 方面的知识; 18 | 19 | 2. 在某个套接字上监听 TCP 连接; 20 | 21 | 3. 解析少数几个 HTTP 请求; 22 | 23 | 4. 创建出某种恰当的 HTTP 响应; 24 | 25 | 5. 运用线程池,提升咱们服务器的吞吐量。 26 | 27 | 28 | 在咱们开始动手前,咱们应注意到一个情况:咱们将运用的方法,将不会是在 Rust 下构建 web 服务器的最佳方法。在 [crates.io](https://crates.io/) 上,一些社区成员已经发布了数个,适合用于生产环境,提供了更完整功能的 web 服务器,以及咱们将要构建的线程池实现的代码箱。但是,本章中咱们的意图,是要帮助咱们学习掌握,而非走那样的捷径。由于 Rust 是门系统编程语言,因此咱们可以选择咱们打算着手的抽象层次,并可以触及到相比其他语言中,可行的或可操作的更低级别。因此咱们将亲自编写这个基本的 HTTP 服务器与线程池,如此咱们便可以学习这些代码箱之后的,今后可能会用到的一些一般概念与技巧。 29 | 30 | 31 | -------------------------------------------------------------------------------- /projects/encapsulation_demo/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_variables)] 3 | 4 | pub struct AveragedCollection { 5 | list: Vec, 6 | average: f64, 7 | } 8 | 9 | impl AveragedCollection { 10 | pub fn add(&mut self, value: i32) { 11 | self.list.push(value); 12 | self.update_average(); 13 | } 14 | 15 | pub fn remove(&mut self) -> Option { 16 | let result = self.list.pop(); 17 | match result { 18 | Some(value) => { 19 | self.update_average(); 20 | Some(value) 21 | } 22 | None => None, 23 | } 24 | } 25 | 26 | pub fn average(&self) -> f64 { 27 | self.average 28 | } 29 | 30 | fn update_average(&mut self) { 31 | let total: i32 = self.list.iter().sum(); 32 | self.average = total as f64 / self.list.len() as f64; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /projects/neo_simple_blog/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub struct Post { 2 | content: String, 3 | } 4 | 5 | pub struct DraftPost { 6 | content: String, 7 | } 8 | 9 | impl Post { 10 | pub fn new() -> DraftPost { 11 | DraftPost { 12 | content: String::new(), 13 | } 14 | } 15 | 16 | pub fn content(&self) -> &str { 17 | &self.content 18 | } 19 | } 20 | 21 | impl DraftPost { 22 | pub fn add_text(&mut self, text: &str) { 23 | self.content.push_str(text); 24 | } 25 | 26 | pub fn request_review(self) -> PendingReviewPost { 27 | PendingReviewPost { 28 | content: self.content, 29 | } 30 | } 31 | } 32 | 33 | pub struct PendingReviewPost { 34 | content: String, 35 | } 36 | 37 | impl PendingReviewPost { 38 | pub fn approve(self) -> Post { 39 | Post { 40 | content: self.content, 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/programming_concepts/comments.md: -------------------------------------------------------------------------------- 1 | # 注释 2 | 3 | **Comments** 4 | 5 | 6 | 所有程序员都努力使自己的代码易于理解,但有时也需要一些额外的解释。在这种情况下,程序员会在源代码中留下 *注释,comments*,编译器会忽略这些注释,但阅读源代码的人可能会发现有用。 7 | 8 | 下面就是个简单的注释: 9 | 10 | ```rust 11 | // hello, world 12 | ``` 13 | 14 | 15 | 在 Rust 中,惯用的注释风格,以两个斜线开始一条注释,而该注释会一直持续到行尾。对于超出单个行的注释,咱们需要在每一行,都包含 `//`,像下面这样: 16 | 17 | 18 | ```rust 19 | // 所以我们要做的事情很复杂,长到我们需要 20 | // 多行注释来完成!呼!希望这条注释能 21 | // 解释发生了什么。 22 | ``` 23 | 24 | 25 | 注释也可以放在包含了代码行的末尾: 26 | 27 | 28 | 文件名:`src/main.rs` 29 | 30 | ```rust 31 | fn main() { 32 | let lucky_number = 7; // 今天我感受到了好运 33 | } 34 | ``` 35 | 36 | 但咱们更经常看到的是,将注释放在其所注释代码上方单独一行,这种形式: 37 | 38 | 39 | 文件名:`src/main.rs` 40 | 41 | ```rust 42 | fn main() { 43 | // 今日感到幸运 44 | let lucky_number = 7; 45 | } 46 | ``` 47 | 48 | Rust 还有另一种注释,即文档注释,documentation comments,我们将在第 14 章 [“将 Crate 发布到 Crates.io”](../crates-io/publishing.md) 一节中讨论。 49 | 50 | 51 | (End) 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/Ch19_Advanced_Features.md: -------------------------------------------------------------------------------- 1 | # 高级特性 2 | 3 | **Advanced Features** 4 | 5 | 到此时,咱们业已学习了 Rust 编程语言的那些最为常用部分。在第 20 章中咱们完成另一个项目之前,将看看咱们可能会偶尔碰到,但却不会每天用到的这门语言的一些方面。咱们可将这一章,当作在今后遇到一些不明白之处时的一份参考。这里所涵盖的特性,在一些非常特定情形下是有用的。尽管咱们可能不会经常碰到这些情形,咱们还是希望,能掌握 Rust 所提供到的全部特性。 6 | 7 | 咱们将在这一章,涵盖以下内容: 8 | 9 | - 不安全的 Rust, unsafe Rust: 怎样选择不使用 Rust 的一些保证,而由程序员亲自负责维持这些保证; 10 | 11 | + 一些高级特质,advanced traits: 12 | - 关联类型,associated types; 13 | - 默认类型参数,default type parameters; 14 | - 完全合格语法,fully qualified syntax; 15 | - 超特质,supertraits; 16 | - 及与特质相关的新型模式,the newtype pattern in relation to traits。 17 | 18 | + 一些高级类型: 19 | - 更多有关新型模式的内容; 20 | - 类型别名,type aliases; 21 | - 永恒类型,the never type; 22 | - 以及动态大小的类型,dynamically sized types。 23 | 24 | - 高级函数与高级闭包:函数指针与返回的闭包,function pointers and returning closures; 25 | 26 | - 宏,macros:那些在编译时定义了别的代码的代码定义方式,ways to define code that defines more code at compile time。 27 | 28 | 29 | 本章是给每个人应该了解的,一整套 Rust 特性!咱们就开始吧! 30 | 31 | 32 | -------------------------------------------------------------------------------- /projects/operator_overloading/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Add; 2 | 3 | #[derive(Debug, Copy, Clone, PartialEq)] 4 | struct Point { 5 | x: i32, 6 | y: i32, 7 | } 8 | 9 | impl Add for Point { 10 | type Output = Point; 11 | 12 | fn add(self, other: Point) -> Point { 13 | Point { 14 | x: self.x + other.x, 15 | y: self.y + other.y, 16 | } 17 | } 18 | } 19 | 20 | 21 | #[derive(Debug, Copy, Clone, PartialEq)] 22 | struct Millimeters(u32); 23 | 24 | #[derive(Debug, Copy, Clone, PartialEq)] 25 | struct Meters(u32); 26 | 27 | impl Add for Millimeters { 28 | type Output = Millimeters; 29 | 30 | fn add(self, other: Meters) -> Millimeters { 31 | Millimeters(self.0 + (other.0 * 1000)) 32 | } 33 | } 34 | 35 | fn main() { 36 | assert_eq! ( 37 | Point { x: 1, y: 0 } + Point { x: 2, y: 3}, 38 | Point { x: 3, y: 3 } 39 | ); 40 | 41 | assert_eq! ( 42 | Millimeters(50) + Meters(1), 43 | Millimeters(1050) 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /projects/rectangles/src/main.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | struct Rectangle { 3 | width: u32, 4 | height: u32, 5 | } 6 | 7 | impl Rectangle { 8 | fn area(&self) -> u32 { 9 | self.width * self.height 10 | } 11 | 12 | fn can_hold(&self, other: &Rectangle) -> bool { 13 | (self.width > other.width && self.height > other.height) 14 | || (self.width > other.height && self.height > other.width) 15 | } 16 | 17 | fn square(size: u32) -> Self { 18 | Self { 19 | width: size, 20 | height: size, 21 | } 22 | } 23 | } 24 | 25 | fn main() { 26 | let rect1 = Rectangle { 27 | width: 30, 28 | height: 50, 29 | }; 30 | 31 | let rect2 = Rectangle { 32 | width: 10, 33 | height: 40, 34 | }; 35 | 36 | let rect3 = Rectangle { 37 | width: 48, 38 | height: 28, 39 | }; 40 | 41 | println! ("rect1 可以容纳 rect2 吗?{}", rect1.can_hold(&rect2)); 42 | println! ("rect1 可以容纳 rect3 吗?{}", rect1.can_hold(&rect3)); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/Ch11_Writing_Automated_Tests.md: -------------------------------------------------------------------------------- 1 | # 编写自动化测试 2 | 3 | 在 Edsgar W. Dijkstra(迪杰斯特拉) 1972 年论文 [《谦卑的程序员(The Humble Programmer)》](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD03xx/EWD340.html)中,迪杰斯特拉指出 “程序测试可以是一种揭示代码存在的非常有效方式,但对于揭示代码错误存在,程序测试又显得不那么足够(Program testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absensce)。” 这并不意味着咱们就不要尽力进行尽可能多的测试! 4 | 5 | 所谓计算机程序正确,即为所编写代码,在多大程度上完成了想要他完成的事情。Rust 是以高度关注程序正确度而设计的,不过正确度是个复杂的问题,而不易于证明。Rust 的类型系统承担了保证正确性的很大部分,但类型系统并不能捕获到所有东西。由于这方面的原因,Rust 包括了编写自动化软件测试的支持。 6 | 7 | 这里假设说编写了一个将 `2` 加到所传入任何数字的一个函数 `add_two`。该函数的签名,会接受某个整数作为参数,并返回一个整数作为计算结果。在实现并编译那个函数时,Rust 会完成至此所掌握的全部类型检查与借用检查,来确保比如这里没有传递某个 `String` 值,或传递某个无效引用到该函数。但 Rust *无法* 就该函数将准确完成咱们所想要的操作,即返回参数加 `2`,而非参数加 `10` 或者参数减去 `50` 进行检查!这正是测试发挥作用的地方。 8 | 9 | 可编写出进行假定的一些测试来,比如,在将 `3` 传递给这个 `add_two` 函数时,返回的值就是 `5`。每当修改了代码时,就都可以运行这些测试,来确保车关系的任何既有正确行为,没有发生变化。 10 | 11 | 测试是门综合技能:尽管这里无法在一章中,涉及到怎样编写良好测试的方方面面,这里还是会对 Rust 各种测试设施的机制进行讨论。这里会讲到在编写测试时,可用的注解与宏,运行测试的默认动作与选项,以及怎样将一些测试,组织为单元测试与集成测试(unit tests and integration tests)。 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/local_serving.md: -------------------------------------------------------------------------------- 1 | ## 在本地阅读 2 | 3 | 在本地阅读本书,需要安装 `mdbook` 程序。根据操作系统的不同,安装 `mdbook` 程序有所不同。 4 | 5 | 6 | ### 在 Linux 系统上 7 | 8 | ```console 9 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 10 | cargo install mdbook 11 | ``` 12 | 13 | ### 在 Windows 上 14 | 15 | 在 “Powershell(管理员)”("Administrator: Windows Powershell") 中,先安装 `choco` 16 | 17 | ```powershell 18 | Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) 19 | ``` 20 | 21 | 经由 `choco` 安装 `msys2` 22 | 23 | ```powershell 24 | choco install -y msys2 25 | ``` 26 | 27 | 在 `msys2` 中安装 `mdbook` 28 | 29 | ```console 30 | pacman -S mingw-w64-x86_64-mdbook 31 | ``` 32 | 33 | 安装好 `mdbook` 后, 带一些命令行参数和开关运行服务器: 34 | 35 | ```console 36 | mdbook serve ~/rust-lang-zh_CN -p 8080 -n 127.0.0.1 --open 37 | ``` 38 | 39 | > 注:当在 Windows 系统上时,咱们要在 `msys2` 的终端窗口中运行此命令。 40 | 41 | 此时,将在操作系统的默认浏览器中,打开本书。 42 | 43 | 44 | 45 | 46 | (End) 47 | 48 | 49 | -------------------------------------------------------------------------------- /projects/mp_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_variables)] 3 | 4 | use std::sync::mpsc; 5 | use std::thread; 6 | use std::time::Duration; 7 | 8 | fn main() { 9 | let (tx, rx) = mpsc::channel(); 10 | 11 | let tx1 = tx.clone(); 12 | thread::spawn(move || { 13 | let vals = vec! [ 14 | String::from("你好"), 15 | String::from("自"), 16 | String::from("此"), 17 | String::from("线程"), 18 | ]; 19 | 20 | for val in vals { 21 | tx1.send(val).unwrap(); 22 | thread::sleep(Duration::from_millis(500)); 23 | } 24 | }); 25 | 26 | thread::spawn(move || { 27 | let vals = vec! [ 28 | String::from("给"), 29 | String::from("你"), 30 | String::from("一些别的"), 31 | String::from("消息"), 32 | ]; 33 | 34 | for val in vals { 35 | tx.send(val).unwrap(); 36 | thread::sleep(Duration::from_millis(500)); 37 | } 38 | }); 39 | 40 | for received in rx { 41 | println! ("收到:{}", received); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /projects/nth_fibonacci/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use num_format::{Locale, ToFormattedString}; 3 | // use std::process; 4 | 5 | fn nth_fibonacci(n: u64) -> u64 { 6 | 7 | if n == 0 || n == 1 { 8 | return n; 9 | } else { 10 | return nth_fibonacci(n - 1) + nth_fibonacci(n - 2); 11 | } 12 | } 13 | 14 | fn main() { 15 | println! ("找出第 n 个斐波拉基数"); 16 | 17 | 'main_loop: loop { 18 | println! ("请输入 n: (Q/quit 退出程序)"); 19 | 20 | let n: u64 = loop { 21 | let mut tmp = String::new(); 22 | 23 | io::stdin() 24 | .read_line(&mut tmp) 25 | .expect("读取输入失败!"); 26 | 27 | let tmp = tmp.trim(); 28 | 29 | if tmp.eq("Q") || tmp.eq("quit") { 30 | // process::exit(0); 31 | break 'main_loop; 32 | } 33 | 34 | match tmp.parse() { 35 | Ok(num) => { break num }, 36 | Err(_) => { 37 | println! ("请输入一个正整数!\n"); 38 | continue; 39 | }, 40 | }; 41 | }; 42 | 43 | println! ("第 {} 个斐波拉基数为:{}", 44 | n, 45 | nth_fibonacci(n).to_formatted_string(&Locale::en)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /projects/aggregator/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub trait Summary { 2 | fn summarize_author(&self) -> String; 3 | 4 | fn summarize(&self) -> String { 5 | format! ("(了解更多来自 {} ......)", self.summarize_author()) 6 | } 7 | } 8 | 9 | pub struct NewsArticle { 10 | pub headline: String, 11 | pub location: String, 12 | pub author: String, 13 | pub content: String, 14 | } 15 | 16 | impl Summary for NewsArticle { 17 | fn summarize_author(&self) -> String { 18 | format! ("{}", self.author) 19 | } 20 | } 21 | 22 | pub struct Tweet { 23 | pub username: String, 24 | pub content: String, 25 | pub reply: bool, 26 | pub retweet: bool, 27 | } 28 | 29 | impl Summary for Tweet { 30 | fn summarize_author(&self) -> String { 31 | format! ("@{}", self.username) 32 | } 33 | } 34 | 35 | use std::fmt::Display; 36 | 37 | pub struct Pair { 38 | pub x: T, 39 | pub y: T, 40 | } 41 | 42 | impl Pair { 43 | pub fn new(x: T, y: T) -> Self { 44 | Self { x, y } 45 | } 46 | } 47 | 48 | impl Pair { 49 | pub fn cmp_display(&self) { 50 | if self.x >= self.y { 51 | println! ("极大数为 x = {}", self.x); 52 | } else { 53 | println! ("极大数为 y = {}", self.y); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Ch07_Managing_Growing_Projects_with_Packages_Crates_and_Modules.md: -------------------------------------------------------------------------------- 1 | # 使用包、代码箱与模组管理不断增长的项目 2 | 3 | **Managing Growing Projects with Packages, Crates and Modules** 4 | 5 | 6 | 当咱们编写大型程序时,组织咱们的代码,将变得日益重要。通过对相关功能进行分组,并将具有不同功能的代码分开,咱们就会弄清楚,在哪里可以找到实现某项特定功能的代码,以及在哪里可以改变某项特性的工作方式。 7 | 8 | 到目前为止,我们编写的程序,都是在一个文件的一个模块中。随着项目的增长,咱们应通过把代码拆分为多个模块,然后拆分为多个文件来组织代码。一个包可以包含多个二进制代码箱,也可以包含一个库代码箱。随着包的增长,咱们可以将各个部分,提取到独立的代码箱中,成为外部依赖。本章将介绍所有这些技巧。对于由一组相互关联,共同发展的包组成的超大型项目,Cargo 提供了 *工作空间,workspaces*,我们将在第 14 章的 [Cargo 工作空间](../crates-io/workspace.md) 小节中介绍。 9 | 10 | 我们还将讨论对实现细节进行封装的问题,这可以让咱们在更高层次上重用代码:一旦咱们实现了某个操作,其他代码就可以通过其公共接口,调用你的代码,而不必知道该操作是如何实现的。咱们编写代码的方式,定义了哪些部分是公开供其他代码使用的,哪些部分是私有的,咱们保留更改权利的实现细节。这是减少咱们必须记住的细节数量(从而减轻编程者负担)的方法。 11 | 12 | 一个相关的概念是作用域:代码被写下之处的嵌套上下文,有着一组被定义为 “在作用域中” 的名字。在读取、编写和编译代码时,程序员和编译器都需要知道,某个特定点位上的特定名字,是否引用了某个变量、函数、结构体、枚举、模组、常量,或其他项目,以及该项目的含义。咱们可以创建出作用域,并改变哪些名字,在作用域内,哪些在作用域外。在同一个作用域中,不能有两个同名的项目;有些工具,可以解决名字冲突问题。 13 | 14 | Rust 有数项特性,可以让咱们管理咱们代码的组织,包括哪些细节是公开的,哪些细节是私有的,以及咱们程序中各个作用域中的有哪些名字。这些特性有时统称为 *模组系统*,包括: 15 | 16 | 17 | - **包,packages**:让咱们构建、测试和共享代码箱的 Cargo 特性; 18 | 19 | - **代码箱,crates**:产生库或可执行程序的模组树; 20 | 21 | - **模组,modules** 与 **`use` 关键字**:让咱们控制路径的组织、作用域和隐私; 22 | 23 | - **路径,paths**:命名项目(例如结构体、函数或模块)的一种方式。 24 | 25 | 26 | 在本章中,我们将介绍所有这些功能,讨论他们如何交互,并探讨如何使用他们来管理作用域。到本章结束时,咱们应对模组系统有扎实的了解,并能像专业人士一样,使用作用域! 27 | 28 | 29 | -------------------------------------------------------------------------------- /projects/minigrep/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(warnings)] 2 | // 3 | // this is to disable warnings. 4 | // Comment it to enable warnings. 5 | // 6 | use std::error::Error; 7 | use std::fs; 8 | use data_structures::Config; 9 | // 10 | // 以下两种写法,也是可以的 11 | // 12 | // use self::data_structures::Config; 13 | // use crate::data_structures::Config; 14 | 15 | #[cfg(test)] 16 | mod tests; 17 | pub mod data_structures; 18 | 19 | pub fn run( 20 | config: Config 21 | ) -> Result<(), Box> { 22 | let contents = fs::read_to_string(config.file_path)?; 23 | 24 | let results: Vec<&str> = if config.ignore_case { 25 | search_insensitive(&config.query, &contents) 26 | } else { 27 | search(&config.query, &contents) 28 | }; 29 | 30 | for line in results { 31 | println! ("{line}"); 32 | } 33 | 34 | Ok(()) 35 | } 36 | 37 | pub fn search<'a>( 38 | query: &str, 39 | contents: &'a str 40 | ) -> Vec<&'a str> { 41 | contents 42 | .lines() 43 | .filter(|line| line.contains(query)) 44 | .collect() 45 | } 46 | 47 | pub fn search_insensitive<'a>( 48 | query: &str, 49 | contents: &'a str 50 | ) -> Vec<&'a str> { 51 | let query = query.to_lowercase(); 52 | 53 | contents 54 | .lines() 55 | .filter(|line| line.to_lowercase().contains(&query)) 56 | .collect() 57 | } 58 | -------------------------------------------------------------------------------- /projects/hello/src/main.rs: -------------------------------------------------------------------------------- 1 | use hello::ThreadPool; 2 | 3 | use std::{ 4 | fs, 5 | thread, 6 | io::{prelude::*, BufReader}, 7 | net::{TcpListener, TcpStream}, 8 | time::Duration, 9 | }; 10 | 11 | fn main() { 12 | let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); 13 | let pool = ThreadPool::new(4); 14 | 15 | for stream in listener.incoming().take(2) { 16 | let stream = stream.unwrap(); 17 | 18 | pool.execute(|| { 19 | handle_conn(stream); 20 | }); 21 | } 22 | 23 | println! ("关闭中。"); 24 | } 25 | 26 | fn handle_conn(mut stream: TcpStream) { 27 | let buf_reader = BufReader::new(&mut stream); 28 | let req_line = buf_reader.lines().next().unwrap().unwrap(); 29 | 30 | let (status_line, filename) = match &req_line[..] { 31 | "GET / HTTP/1.1" => ( "HTTP/1.1 200 OK", "hello.html"), 32 | "GET /sleep HTTP/1.1" => { 33 | thread::sleep(Duration::from_secs(10)); 34 | ("HTTP/1.1 200 0K", "hello.html") 35 | } 36 | _ => ("HTTP/1.1 404 NOT FOUND", "404.html"), 37 | }; 38 | 39 | let contents = fs::read_to_string(filename).unwrap(); 40 | let length = contents.len(); 41 | 42 | let resp = 43 | format! ("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}"); 44 | 45 | stream.write_all(resp.as_bytes()).unwrap(); 46 | } 47 | -------------------------------------------------------------------------------- /projects/ref_cycle_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::rc::Rc; 3 | use crate::List::{Cons, Nil}; 4 | 5 | #[derive(Debug)] 6 | enum List { 7 | Cons(i32, RefCell>), 8 | Nil, 9 | } 10 | 11 | impl List { 12 | fn tail(&self) -> Option<&RefCell>> { 13 | match self { 14 | Cons(_, item) => Some(item), 15 | Nil => None, 16 | } 17 | } 18 | } 19 | 20 | fn main() { 21 | let a = Rc::new( 22 | Cons( 23 | 5, 24 | RefCell::new(Rc::new(Nil)) 25 | ) 26 | ); 27 | 28 | println! ("a 的初始 rc 计数 = {}", Rc::strong_count(&a)); 29 | println! ("a 的下一条目 = {:?}", a.tail()); 30 | 31 | let b = Rc::new( 32 | Cons( 33 | 10, 34 | RefCell::new(Rc::clone(&a)) 35 | ) 36 | ); 37 | 38 | println! ("创建 b 后 a 的 rc 计数 = {}", Rc::strong_count(&a)); 39 | println! ("b 的初始 rc 计数 = {}", Rc::strong_count(&b)); 40 | println! ("b 的下一条目 = {:?}", b.tail()); 41 | 42 | if let Some(link) = a.tail() { 43 | *link.borrow_mut() = Rc::clone(&b); 44 | } 45 | 46 | println! ("在修改 a 之后 b 的 rc 计数 = {}", Rc::strong_count(&b)); 47 | println! ("在修改 a 之后 a 的 rc 计数 = {}", Rc::strong_count(&a)); 48 | 49 | // 取消下面这行注释,就可以看到这里有着循环引用; 50 | // 他将溢出堆栈(it will overflow the stack) 51 | // println! ("a 的下一条目 = {:?}", a.tail()); 52 | } 53 | -------------------------------------------------------------------------------- /src/appendix/editions.md: -------------------------------------------------------------------------------- 1 | # 附录 E:关于版本 2 | 3 | **Appendix E - Editions** 4 | 5 | 在第一章中,咱们曾看到 `cargo new` 会把一点有关某个版的元数据,添加到咱们的 `Cargo.toml` 文件。此附录就会讲到那意味着什么! 6 | 7 | Rust 语言及编译器有着六周的发布周期,意味着用户会得到源源不断的新功能。其他编程语言会不经常地发布较大变更;Rust 则会更频繁发布较小的更新。不久之后,全部这些小修改就会堆积起来。不过这一个个发布中,回头看看而讲到,“噢,从版本 1.10 到 1.31,Rust 改变了很多!”。则是不容易的。 8 | 9 | 每两三年,Rust 团队都会产生一个新的 Rust *版本,edition*。每个版本都会以完全更新的文档与工具,将那些业已落地到一个明确包中的特性放到一起。新版本会作为寻常的六周发布过程而交付。 10 | 11 | 这些版本服务了不同人群的不同目的: 12 | 13 | - 对于活跃的 Rust 用户,新版本会把那些增量变更,一起放入到一个易于掌握的包中; 14 | - 对于那些非用户,新版本释放了一些已落地的大进展信号,这会让 Rust 或许值得再看一看; 15 | - 对于开发 Rust 的人们,新版本会提供这个项目作为整体的集结点。 16 | 17 | 在本书编写时,已有三个 Rust 版本可用:Rust 2015、Rust 2018 与 Rust 2021。本书是用 Rust 2021 版本的习惯用语编写的。 18 | 19 | `Cargo.toml` 中的 `edition` 键,表示应对咱们的代码使用哪个版本的编译器。若该键不存在,Rust 就会以向后兼容原因,而使用 `2015` 作为版本值。 20 | 21 | 每个项目都可以选择一个不同于默认 2015 的版本。这些版本可能包含了不兼容的变更,比如包含了与代码中标识符冲突的新关键字。但是,除非咱们选到这些变更,那么即使咱们更新了所使用的 Rust 编译器,咱们的代码将继续编译。 22 | 23 | 全部 Rust 编译器版本,都会支持先于那个编译器发布而存在的任何版本,且他们可将任何受支持版本的代码箱连接起来。版本变更只会影响编译器于编译初期解析代码的方式。因此,当咱们正使用着 Rust 2015,而咱们的一项依赖使用了 Rust 2018 时,咱们的项目将编译,并能够使用那项依赖。与之相反,在咱们的项目使用 Rust 2018,而一项依赖使用了 Rust 2015 的情形下,也会工作。 24 | 25 | 要明确的是:绝大多数特性,在所有版本上都将可用。使用任何 Rust 版本的开发者,都将在新的稳定发布构造出来时,发现一些改进。但是,在一些情况下,主要是在新曾了关键字时,一些新特性就会只在稍后版本中可用了。若咱们打算利用上这些新特性,咱们将需要切换版本。 26 | 27 | 有关更多细节,[版本指南,Edition Guide](https://doc.rust-lang.org/stable/edition-guide/) 是本列举了不同版本间差异,并解释了怎样通过 `cargo fix`,而自动将咱们的代码更新到新版的一本完整的书。 28 | 29 | 30 | (End) 31 | 32 | 33 | -------------------------------------------------------------------------------- /projects/tree_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::rc::{Rc, Weak}; 3 | 4 | #[derive(Debug)] 5 | struct Node { 6 | value: i32, 7 | parent: RefCell>, 8 | children: RefCell>>, 9 | } 10 | 11 | fn main() { 12 | let leaf = Rc::new(Node { 13 | value: 3, 14 | parent: RefCell::new(Weak::new()), 15 | children: RefCell::new(vec! []), 16 | }); 17 | 18 | println! ( 19 | "叶子节点的强引用计数:{},弱引用计数:{}\n", 20 | Rc::strong_count(&leaf), 21 | Rc::weak_count(&leaf), 22 | ); 23 | 24 | { 25 | let branch = Rc::new(Node { 26 | value: 5, 27 | parent: RefCell::new(Weak::new()), 28 | children: RefCell::new(vec! [Rc::clone(&leaf)]), 29 | }); 30 | 31 | *leaf.parent.borrow_mut() = Rc::downgrade(&branch); 32 | 33 | println! ( 34 | "枝干节点的强引用计数:{},弱引用计数:{}\n", 35 | Rc::strong_count(&branch), 36 | Rc::weak_count(&branch), 37 | ); 38 | println! ( 39 | "叶子节点的强引用计数:{},弱引用计数:{}\n", 40 | Rc::strong_count(&leaf), 41 | Rc::weak_count(&leaf), 42 | ); 43 | 44 | } 45 | println! ("叶子节点的父节点 = {:?}\n", leaf.parent.borrow().upgrade()); 46 | println! ( 47 | "叶子节点的强引用计数:{},弱引用计数:{}\n", 48 | Rc::strong_count(&leaf), 49 | Rc::weak_count(&leaf), 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /projects/closure_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Copy, Clone)] 2 | enum ShirtColor { 3 | Red, 4 | Blue, 5 | } 6 | 7 | struct Inventory { 8 | shirts: Vec, 9 | } 10 | 11 | impl Inventory { 12 | fn giveaway( 13 | &self, 14 | user_preference: Option 15 | ) -> ShirtColor { 16 | user_preference.unwrap_or_else(|| self.most_stocked()) 17 | } 18 | 19 | fn most_stocked(&self) -> ShirtColor { 20 | let mut num_red = 0; 21 | let mut num_blue = 0; 22 | 23 | for color in &self.shirts { 24 | match color { 25 | ShirtColor::Red => num_red += 1, 26 | ShirtColor::Blue => num_blue += 1, 27 | } 28 | } 29 | 30 | if num_red > num_blue { 31 | ShirtColor::Red 32 | } else { 33 | ShirtColor::Blue 34 | } 35 | } 36 | } 37 | 38 | fn main() { 39 | let store = Inventory { 40 | shirts: vec! [ShirtColor::Blue, ShirtColor::Red, ShirtColor::Blue], 41 | }; 42 | 43 | let user_pref1 = Some(ShirtColor::Red); 44 | let giveaway1 = store.giveaway(user_pref1); 45 | println! ( 46 | "选项为 {:?} 的用户,得到了 {:?}", 47 | user_pref1, giveaway1 48 | ); 49 | 50 | let user_pref2 = None; 51 | let giveaway2 = store.giveaway(user_pref2); 52 | println! ( 53 | "选项为 {:?} 的用户得到了 {:?}", 54 | user_pref2, giveaway2 55 | ); 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/Ch12_An_IO_Project_Building_a_Command_Line_Program.md: -------------------------------------------------------------------------------- 1 | # 一个文件系统 I/O 项目:构建一个命令行程序 2 | 3 | 这一章是对到目前为止所学到技能的一个回顾,又是对少数几个另外标准库特性的一个探索。这里将构建一个与文件及命令行输入输出进行交互的命令行工具,来练习咱们现在掌握到的一些 Rust 概念。 4 | 5 | Rust 的速度、安全性、单一二进制可执行程序输出,还有跨平台支持,令其成为创建命令行工具的理想编程语言,那么对于这个项目,这里将构造自己版本的那个经典的命令行搜索工具 `grep` (**g**lobally search a **r**egular **e**xpression and **p**rint,正则表达式全局搜索及打印程序)。在最简单用例中,`grep` 会对某个指定文件,就某个指定字符串而加以搜索。为完成这个目的,`grep` 就会取一个文件路径与一个字符串作为其命令行参数。随后他会读取那个文件,找到那个文件中包含有该字符串参数的那些行,并打印出这些行。 6 | 7 | 在构造这个命令行程序的道路上,这里将展示如何让这个命令行工具,使用到其他命令行工具都会用到的一些终端特性(the terminal features)。这里将读取某个环境变量的值,来允许使用者对这个工具默认行为进行配置。这里还会将错误消息打印到标准错误控制台的流(the standard error console stream, `stderr`),而非打印到标准输出(`stdout`),如此一来,用户就可以将成功的输出重定向到某个文件,而仍能从屏幕上看到错误消息,并有着其他一些好处。 8 | 9 | 名为 Andrew Gallant 的一位 Rust 社区成员,就已经创建了一个特性完整、非常快版本的 `grep`,名叫 [`ripgrep`](https://github.com/BurntSushi/ripgrep)。相比之下,这个版本将相当简单,不过这一章将给到一些掌握诸如 `ripgrep` 这样的真实项目,所需的背景知识。 10 | 11 | 这个 `grep` 项目,将结合至今所掌握的下面几个到目前为止已掌握的概念: 12 | 13 | - 对代码进行组织(使用 [第 7 章](Ch07_Managing_Growing_Projects_with_Packages_Crates_and_Modules.md) 中所掌握的有关模组的知识) 14 | - 对矢量值与字符串的使用(集合,[第 8 章](Ch08_Common_Collections.md)) 15 | - 对错误的处理([第 9 章](Ch09_Error_Handling.md)) 16 | - 在恰当之处使用特质与生命周期([第 10 章](Ch10_Generic_Types_Traits_and_Lifetimes.md)) 17 | - 编写测试([第 11 章](Ch11_Writing_Automated_Tests.md)) 18 | 19 | 这里还会简要对闭包、迭代器及特质对象等,进行简要介绍,后面的 [第 13 章](Ch13_Functional_Languages_Features_Iterator_and_Closures.md) 与 [第 17 章](Object_Oriented_Programming_Features_of_Rust.md) 等章节,将详细讲解到这些特性。 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Ch15_Smart_Pointers.md: -------------------------------------------------------------------------------- 1 | # 灵巧指针 2 | 3 | **Smart Pointers** 4 | 5 | 所谓 *指针,pointer*,是个一般的概念,指的是包含了内存中某个地址的变量。该地址引用,或者说 “指向” 另一数据。Rust 中最常见的指针类别,便是咱们在第 4 章中曾了解过的引用。引用由 `&` 符号表示,并借用他们指向的值。除了引用数据之外,他们没有任何特殊功能,并且没有开销。 6 | 7 | 另一方面,*灵巧指针,smart pointer* 是一种数据结构,其作用类似于指针,但还具有额外的元数据与能力。灵巧指针这个概念,并非 Rust 所独有的:灵巧指针起源于 C++,且在其他语言中也存在。Rust 在标准库中定义了各种灵巧指针,他们提供了超越引用所提供的功能。为了探讨一般概念,我们将看几个不同的灵巧指针示例,包括 *引用计数,reference counting* 灵巧指针类型。引用计数这种指针,通过追踪数据所有者的数目,实现了允许数据有着多个所有者,在没有所有者剩下时,就清除该数据。 8 | 9 | 在所有权和借用的概念下,Rust 在引用和灵巧指针之间还有一个区别:引用只借用数据,而在很多情况下,灵巧指针则 *拥有,own* 他们所指向的数据。 10 | 11 | 虽然当时咱们没有这样称呼他们,但在本书中我们已经遇到了一些灵巧指针,包括第 8 章中的 `String` 和 `Vec`。这两种类型都算作灵巧指针,因为他们拥有一些内存,并允许咱们对其进行操作。他们也有元数据和额外的能力或保证。例如,`String` 将其容量存储为元数据,并有额外的能力来确保其数据将始终是有效的 UTF-8。 12 | 13 | 灵巧指针通常是使用结构体来实现的。与寻常结构体不同,灵巧指针实现了 `Deref` 与 `Drop` 特质。`Deref` 特质允许灵巧指针结构体实例像引用那样行事,如此咱们便可编写出处理引用或灵巧指针的代码。而 `Drop` 特质则允许咱们定制在灵巧指针超出作用域时要运行的代码。本章中,咱们将讨论这两种特质,并演示他们为何对灵巧指针很重要。 14 | 15 | 鉴于灵巧指针模式是 Rust 中频繁用到的一种通用设计模式,本章不会涵盖每个既有灵巧指针。许多库都有自己的灵巧指针,咱们甚至也可以编写自己的灵巧指针。咱们将介绍标准库中最常见的灵巧指针: 16 | 17 | - 用于在内存堆上分配值的 `Box`; 18 | - `Rc`,一个引用计数类型,可以实现多重所有权,`Rc`, a reference counting type that enables multiple ownership; 19 | - `Ref` 和 `RefMut`,通过 `RefCell` 访问,该类型在运行时而不是编译时执行借用规则检查,`Ref` and `RefMut`, accessed through `RefCell`, a type that enforces the borrowing rules at runtime instead of compile time。 20 | 21 | 此外,咱们还将讨论 *内部可变性,interior mutability* 模式,在这种模式下,不可变的类型会暴露出一个用于改变内部值的 API。我们还将讨论引用循环:他们如何泄漏内存以及如何防止他们。 22 | 23 | 下面就来切入正题吧! 24 | 25 | 26 | -------------------------------------------------------------------------------- /projects/aggregator/src/main.rs: -------------------------------------------------------------------------------- 1 | use aggregator::{Summary, Tweet, NewsArticle, Pair}; 2 | 3 | pub fn notify(item: &T) { 4 | println! ("突发新闻!{}", item.summarize()); 5 | } 6 | 7 | fn return_summarizable() -> impl Summary { 8 | Tweet { 9 | username: String::from("horse_ebooks"), 10 | content: String::from( 11 | "当然,如同你或许已经知道的一样,朋友们" 12 | ), 13 | reply: false, 14 | retweet: false, 15 | } 16 | } 17 | 18 | fn main() { 19 | let tweet = Tweet { 20 | username: String::from("horse_ebooks"), 21 | content: String::from( 22 | "当然,跟大家已经清楚的一样了,朋友们", 23 | ), 24 | reply: false, 25 | retweet: false, 26 | }; 27 | 28 | println!("1 条新推文: {}", tweet.summarize()); 29 | notify(&tweet); 30 | 31 | 32 | let article = NewsArticle { 33 | headline: String::from("企鹅队赢得斯坦利杯锦标赛!"), 34 | location: String::from("美国,宾夕法尼亚州,匹兹堡"), 35 | author: String::from("Iceburgh"), 36 | content: String::from( 37 | "匹兹堡企鹅队再度成为美国曲棍球联盟 \ 38 | NHL 中的最佳球队。" 39 | ), 40 | }; 41 | 42 | println! ("有新文章可读!{}", article.summarize()); 43 | notify(&article); 44 | 45 | println! ("1 条旧推文: {}", return_summarizable().summarize()); 46 | 47 | let pair = Pair::new(5, 10); 48 | pair.cmp_display(); 49 | 50 | let pair = Pair::new("这是一个测试", "This is a test."); 51 | pair.cmp_display(); 52 | 53 | println! ("{}", 3.to_string()); 54 | } 55 | -------------------------------------------------------------------------------- /theme/pagetoc.css: -------------------------------------------------------------------------------- 1 | @media only screen and (max-width:1439px) { 2 | .sidetoc { 3 | display: none; 4 | } 5 | #search-toggle { 6 | display: none; 7 | } 8 | } 9 | 10 | 11 | @media only screen and (min-width:1440px) { 12 | main { 13 | position: relative; 14 | margin-left: calc((100% - var(--content-max-width))/2 - 140px) !important; 15 | } 16 | .sidetoc { 17 | margin-left: auto; 18 | margin-right: auto; 19 | left: calc(100% + (var(--content-max-width))/4 - 160px); 20 | position: absolute; 21 | } 22 | .pagetoc { 23 | position: fixed; 24 | width: 320px; 25 | height: calc(100vh - var(--menu-bar-height) - 0.67em * 4); 26 | overflow: auto; 27 | } 28 | .pagetoc a { 29 | border-left: 1px solid var(--sidebar-bg); 30 | color: var(--fg) !important; 31 | display: block; 32 | padding-bottom: 5px; 33 | padding-top: 5px; 34 | padding-left: 10px; 35 | text-align: left; 36 | text-decoration: none; 37 | } 38 | .pagetoc a:hover, 39 | .pagetoc a.active { 40 | background: var(--sidebar-bg); 41 | color: var(--sidebar-fg) !important; 42 | } 43 | .pagetoc .active { 44 | background: var(--sidebar-bg); 45 | color: var(--sidebar-fg); 46 | } 47 | .pagetoc .pagetoc-H2 { 48 | padding-left: 20px; 49 | } 50 | .pagetoc .pagetoc-H3 { 51 | padding-left: 40px; 52 | } 53 | .pagetoc .pagetoc-H4 { 54 | padding-left: 60px; 55 | } 56 | .pagetoc .pagetoc-H5 { 57 | display: none; 58 | } 59 | .pagetoc .pagetoc-H6 { 60 | display: none; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /projects/guessing_game/src/main.rs: -------------------------------------------------------------------------------- 1 | use rand::Rng; 2 | use std::{cmp::Ordering, io, process}; 3 | 4 | fn main() { 5 | loop { 6 | println! ("\n---猜出这个数来!---"); 7 | 8 | let secret_number: u32 = rand::thread_rng().gen_range(1..101); 9 | 10 | // println! ("随机生成的秘密数字为:{}", secret_number); 11 | 12 | loop { 13 | println! ("请输入你猜的数。( ‘Q/quit’ 退出游戏)"); 14 | 15 | let mut guess: String = String::new(); 16 | 17 | io::stdin() 18 | .read_line(&mut guess) 19 | .expect("读取行失败/failed to read line"); 20 | 21 | if guess.trim().eq("Q") || guess.trim().eq("quit") { 22 | process::exit(0); 23 | } 24 | 25 | // let guess: u32 = guess.trim().parse().expect("请输入一个数字!"); 26 | let guess: i32 = match guess.trim().parse() 27 | { 28 | Ok(num) => num, 29 | Err(_) => { 30 | println! ("请输入一个数字!"); 31 | continue 32 | }, 33 | }; 34 | 35 | if guess < 1 || guess > 100 { 36 | println!("秘密数字将在 1 和 100 之间。"); 37 | continue; 38 | } 39 | 40 | match guess.cmp(&secret_number) { 41 | Ordering::Less => println! ("太小!"), 42 | Ordering::Greater => println! ("太大!"), 43 | Ordering::Equal => { 44 | println! ("你赢了!"); 45 | break 46 | }, 47 | } 48 | } 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /projects/improved_guessing_game/src/main.rs: -------------------------------------------------------------------------------- 1 | use rand::Rng; 2 | use std::{cmp::Ordering, io, process}; 3 | 4 | mod guessing_game; 5 | use crate::guessing_game::Guess; 6 | 7 | fn main() { 8 | loop { 9 | println! ("\n---猜出这个数来!---"); 10 | 11 | let secret_number: i32 = rand::rng().random_range(1..101); 12 | 13 | // println! ("随机生成的秘密数字为:{}", secret_number); 14 | 15 | loop { 16 | println! ("请输入你猜的数。( ‘Q/quit’ 退出游戏)"); 17 | 18 | let mut guess: String = String::new(); 19 | 20 | io::stdin() 21 | .read_line(&mut guess) 22 | .expect("读取行失败/failed to read line"); 23 | 24 | if guess.trim().eq("Q") || guess.trim().eq("quit") { 25 | process::exit(0); 26 | } 27 | 28 | // let guess: u32 = guess.trim().parse().expect("请输入一个数字!"); 29 | let guess_number: i32 = match guess.trim().parse() 30 | { 31 | Ok(num) => num, 32 | Err(_) => { 33 | println! ("请输入一个数字!"); 34 | continue 35 | }, 36 | }; 37 | 38 | let guess: Guess = Guess::new(guess_number); 39 | 40 | match guess.value().cmp(&secret_number) { 41 | Ordering::Less => println! ("太小!"), 42 | Ordering::Greater => println! ("太大!"), 43 | Ordering::Equal => { 44 | println! ("你赢了!"); 45 | break 46 | }, 47 | } 48 | } 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /projects/match_demo/src/main.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] // so we can inspect the state in a minute 2 | enum UsState { 3 | Alabama, 4 | Alaska, 5 | Arizona, 6 | Arkansas, 7 | California, 8 | Colorado, 9 | Connecticut, 10 | Delaware, 11 | Florida, 12 | Georgia, 13 | Hawaii, 14 | Idaho, 15 | Illinois, 16 | Indiana, 17 | Iowa, 18 | Kansas, 19 | Kentucky, 20 | Louisiana, 21 | Maine, 22 | Maryland, 23 | Massachusetts, 24 | Michigan, 25 | Minnesota, 26 | Mississippi, 27 | Missouri, 28 | Montana, 29 | Nebraska, 30 | Nevada, 31 | NewHampshire, 32 | NewJersey, 33 | NewMexico, 34 | NewYork, 35 | NorthCarolina, 36 | NorthDakota, 37 | Ohio, 38 | Oklahoma, 39 | Oregon, 40 | Pennsylvania, 41 | RhodeIsland, 42 | SouthCarolina, 43 | SouthDakota, 44 | Tennessee, 45 | Texas, 46 | Utah, 47 | Vermont, 48 | Virginia, 49 | Washington, 50 | WestVirginia, 51 | Wisconsin, 52 | Wyoming, 53 | } 54 | 55 | enum Coin { 56 | Penny, 57 | Nickel, 58 | Dime, 59 | Quarter(UsState), 60 | } 61 | 62 | 63 | fn value_in_cents(coin: Coin) -> u8 { 64 | match coin { 65 | Coin::Penny => 1, 66 | Coin::Nickel => 5, 67 | Coin::Dime => 10, 68 | Coin::Quarter(state) => { 69 | println! ("来自 {:?} 州的 25 美分硬币!", state); 70 | 25 71 | } 72 | } 73 | } 74 | 75 | fn main() { 76 | let coin = Coin::Quarter(UsState::Wyoming); 77 | println!("{}", value_in_cents(coin)); 78 | } 79 | -------------------------------------------------------------------------------- /src/appendix/notes.md: -------------------------------------------------------------------------------- 1 | # 附录 H - 有用笔记 2 | 3 | 此处记录学习及应用 Rust 编程软件过程中,觉得有用的一些东西。 4 | 5 | 6 | ## `cargo-binutils` 7 | 8 | [这个项目](https://github.com/rust-embedded/cargo-binutils) 是 Embbeded-Rust 项目的,而不是 Rust 官方的,但提供了有用的功能。比如查看构建出的二进制程序文件的那些头部: 9 | 10 | 11 | ```console 12 | $ cargo readobj --bin clippy_demo -- --file-headers 13 | Finished dev [unoptimized + debuginfo] target(s) in 0.00s 14 | ELF Header: 15 | Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 16 | Class: ELF64 17 | Data: 2's complement, little endian 18 | Version: 1 (current) 19 | OS/ABI: UNIX - System V 20 | ABI Version: 0 21 | Type: DYN (Shared object file) 22 | Machine: Advanced Micro Devices X86-64 23 | Version: 0x1 24 | Entry point address: 0x86D0 25 | Start of program headers: 64 (bytes into file) 26 | Start of section headers: 4305200 (bytes into file) 27 | Flags: 0x0 28 | Size of this header: 64 (bytes) 29 | Size of program headers: 56 (bytes) 30 | Number of program headers: 12 31 | Size of section headers: 64 (bytes) 32 | Number of section headers: 42 33 | Section header string table index: 41 34 | ``` 35 | 36 | 使用前需要进行如下安装: 37 | 38 | ```console 39 | $ cargo install cargo-binutils 40 | $ rustup component add llvm-tools-preview 41 | ``` 42 | 43 | 44 | 45 | 46 | (End) 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/images/15-02.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | %3 11 | 12 | 13 | 14 | table0 15 | 16 | Cons 17 | 18 | i32 19 | 20 | 21 | Box 22 | 23 | usize 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Ch16_Fearless_Concurrency.md: -------------------------------------------------------------------------------- 1 | # 无惧并发 2 | 3 | **Fearless Concurrency** 4 | 5 | 安全并高效地处理并发编程,是 Rust 的另一主要目标。所谓 *并发编程,concurrent programming*,是指其中程序的各部分独立地执行着,而 *并行编程,parallel programming*,则是指程序的不同部分于同一时间执行,随着越来越多的计算机利用了多处理器的优势,这两种编程范式变得日益重要起来。历史上,这两种情景下的编程,曾是有难度且容易出错的:Rust 就有望来改变这种局面。 6 | 7 | 早期阶段,Rust 团队曾认为确保内存安全与防止并发问题,属于要以不同方法来解决的两个单独挑战。随着时间的推移,团队发现所有权与类型系统,正是有助于管理内存安全,*及* 并发问题的一套强有力的工具!经由利用所有权与类型检查,许多的并发错误,就成了 Rust 中的编译时错误,而非运行时错误。因此,就不再是要咱们,在出现运行时并发错误时,花费大量时间尽力重现那些确切情形,而是那些不正确代码,将拒绝编译,并给出代码问题的错误提示。由此,咱们就可以在编写出错误代码时,而非潜在地于交付代码到生产之后,修复好这些代码。这里将 Rust 此方面的特性,亲切地取名为 *无惧并发,fearless concurrency*。无惧并发实现了编写出不带难以察觉错误的代码,且易于在不引入新代码错误之下,对代码加以重构。 8 | 9 | > **注意**:为简化起见,这里将把许多的这些问题,指为 *并发,concurrency*,而非称作更准确的 *并发及/或并行,concurrency and/or parallel*。若本书是有关并发及/或并行编程的书,那么咱们就会更为具体。对于本章,请在任何提及 *并发* 之处,在内心里将其以 *并发及/或并行* 代换。 10 | 11 | 许多语言在他们所提供的,用于解决并发问题的方案上,都是机械教条主义的。比如,Erlang 有着消息传递方面并发的优雅功能,但在共用线程间状态方面,却只有一些晦涩难懂的的途径,for example, Erlang has elegant functionality for message-passing concurrency, but has only obscure ways to share state between threads。对于这类高级语言来讲,仅支持可行方案的子集,是说得通的一种策略,这是由于高级语言以放弃部分的掌控,而换取到抽象方面的收益。然而,那些底层语言,则被期望在各种情形下,都要提供最具性能的方案,进而在硬件上有着较少抽象。因此,Rust 便提供了用以适合于咱们自己不同情形与需求的各种方式,对问题加以建模的各种工具,therefore, Rust offers a variety of tools for modeling problems in whatever way is appropriate for your situtation and requirements。 12 | 13 | 以下即为本章咱们将涵盖的几个话题: 14 | 15 | - 怎样创建出线程,来在同一时间运行代码的不同片段,how to create threads to run multiple pieces of code at the same time; 16 | 17 | - *消息传递,message-passing* 方面的并发,其中有着于线程间发送消息的一些通道; 18 | 19 | - *状态共用,shared-state* 方面的并发,其中多个线程均对某个数据加以访问; 20 | 21 | - `Sync` 与 `Send` 特质,他们俩把 Rust 并发方面的保证,扩展到 Rust 使用者所定义的类型,以及由标准库所提供的那些类型。 22 | 23 | 24 | -------------------------------------------------------------------------------- /projects/lyrics_of_xmas_carol/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let days = [ 3 | "first", 4 | "second", 5 | "third", 6 | "fourth", 7 | "fifth", 8 | "sixth", 9 | "seventh", 10 | "eighth", 11 | "nineth", 12 | "tenth", 13 | "eleventh", 14 | "twelfth" 15 | ]; 16 | let amounts = [ 17 | "A", 18 | "Two", 19 | "Three", 20 | "Four", 21 | "Five", 22 | "Six", 23 | "Seven", 24 | "Eight", 25 | "Nine", 26 | "Ten", 27 | "Eleven", 28 | "Twelve" 29 | ]; 30 | let things = [ 31 | "partridge in a pear tree", 32 | "turtle doves", 33 | "French hens", 34 | "calling birds", 35 | "golden rings", 36 | "geese-a-laying", 37 | "swans-a-swimming", 38 | "maids-a-milking", 39 | "ladies dancing", 40 | "lords-a-leaping", 41 | "pipers piping", 42 | "drummers drumming", 43 | ]; 44 | 45 | for num in 1..=12 { 46 | println! ("\nOn the {} day of Christmas,\nMy true love gave to me:", 47 | days[num-1]); 48 | for tmp in (0..num).rev() { 49 | if tmp == 0 && num == 1 { 50 | println! ("{} {}.", amounts[tmp], things[tmp]); 51 | } 52 | if tmp == 0 && num != 1 { 53 | println! ("And {} {}.", amounts[tmp].to_lowercase(), things[tmp]); 54 | } 55 | if tmp != 0 { 56 | println! ("{} {},", amounts[tmp], things[tmp]); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/crates-io/release_profiles.md: -------------------------------------------------------------------------------- 1 | # 使用不同发布配置文件,对构建进行定制 2 | 3 | **Customizing Builds with Release Profiles** 4 | 5 | 6 | 在 Rust 中,所谓 *发布配置文件,release profiles*,是带有实现程序员对编译代码有着更多掌控的,一些预定义及可定制的配置文件。相对其他配置文件,每个配置文件都是被独立配置的。 7 | 8 | Cargo 有两个主要发布配置文件:运行 `cargo build` 时 Cargo 用到的 `dev` 配置文件,与运行 `cargo build --release` 时 Cargo 用到的 `release` 配置文件。`dev` 配置文件被定义为有着用于开发的一些良好默认配置,而 `release` 配置文件有着用于发布构建的良好默认配置。 9 | 10 | 从咱们构建的输出中,这些配置文件名字或许不陌生: 11 | 12 | ```console 13 | $ cargo build 14 | Finished dev [unoptimized + debuginfo] target(s) in 0.0s 15 | $ cargo build --release 16 | Finished release [optimized] target(s) in 0.0s 17 | ``` 18 | 19 | 其中 `dev` 及 `release`,即由编译器用到的不同配置文件。 20 | 21 | Cargo 有着在咱们在项目的 `Cargo.toml` 文件中,未曾显式添加任何 `[profile.*]` 小节时,所适用的各个配置文件的默认设置。通过添加咱们打算定制的任何配置文件的 `[profile.*]` 小节,咱们就会覆盖掉默认设置的任何子集。比如,下面是 `dev` 与 `release` 配置文件中 `opt-level` 设置的默认值: 22 | 23 | 文件名:`Cargo.toml` 24 | 25 | ```toml 26 | [profile.dev] 27 | opt-level = 0 28 | 29 | [profile.release] 30 | opt-level = 3 31 | ``` 32 | 33 | 这个 `opt-level` 设置项,控制了 Rust 将应用到咱们代码的优化数目,有着范围 `0` 到 `3` 的取值范围。应用更多优化会延长编译时间,因此若咱们是在开发过程中而频繁编译代码,那么即使产生出的代码运行较慢,咱们也会想要更少的优化来更快地编译。因此默认的 `opt-level` 就是 `0`。而在咱们已准备好发布咱们的代码时,那么就最好用更多时间来编译。咱们将只以发布模式编译一次,但会运行编译好的程序许多次,因此发布模式就以较长的编译时间,换取到运行较快的代码。那就是 `release` 配置文件的 `opt-level` 默认为 `3` 的原因。 34 | 35 | 通过在 `Cargo.toml` 中,给某个默认值添加不同的值,就可以覆盖掉这个默认值。比如,在打算于开发配置文件中使用优化级别 `1` 时,就可以把下面这两行,添加到项目的 `Cargo.toml`: 36 | 37 | 文件名:`Cargo.toml` 38 | 39 | ```toml 40 | [profile.dev] 41 | opt-level = 1 42 | ``` 43 | 44 | 此代码会覆盖默认设置 `0`。现在当咱们运行 `cargo build` 时,Cargo 将使用 `dev` 配置文件的默认设置,加上咱们对 `opt-level` 的定制。由于咱们把 `opt-level` 设置为了 `1`,Cargo 将应用相比于默认设置更多,但不如发布构建那样多的优化。 45 | 46 | 对于各个配置文件的完整配置项清单与默认设置,请参阅 [Cargo 文档](https://doc.rust-lang.org/cargo/reference/profiles.html)。 47 | 48 | 49 | (End) 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/images/trpl17-04.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | fut1 14 | 15 | fut1 16 | 17 | 0 18 | 19 | 1 20 | 21 |   22 | 23 | 24 | 25 | fut1:c->fut1:target 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /projects/fah_to_cels/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::process; 3 | 4 | fn fah_to_cels(f: f32) -> f32 { 5 | return (f - 32.0) / 1.8; 6 | } 7 | 8 | fn cels_to_fah(c: f32) -> f32 { 9 | return c * 1.8 + 32.0; 10 | } 11 | 12 | fn main() { 13 | println! ("法式温度与摄氏温度之间的转换"); 14 | 15 | loop { 16 | println! ("\n-----------------\n请选择: 17 | '1'-摄氏温度/'2'-法式温度/'Q'/\"quit\" 退出程序。 18 | '1'/'2'/'Q'/\"quit\"[1]:"); 19 | 20 | let mut temp_type = String::new(); 21 | 22 | io::stdin() 23 | .read_line(&mut temp_type) 24 | .expect("读取输入失败!"); 25 | 26 | let temp_type = temp_type.trim(); 27 | 28 | if temp_type.eq("Q") || temp_type.eq("quit") { process::exit(0); } 29 | 30 | if ! temp_type.eq("1") && ! temp_type.eq("2") && ! temp_type.eq("") { 31 | println! ("无效输入,请输入 '1'、'2'、'Q'、\"quit\",或直接按下回车键"); 32 | continue; 33 | } 34 | 35 | if temp_type.eq("1") || temp_type.eq("") { 36 | println! ("请输入要转换的摄氏温度:"); 37 | let temp = get_temp_input(); 38 | 39 | println! ("摄氏温度: {:.2}°C,约为法氏温度:{:.2}°F", temp, cels_to_fah(temp)); 40 | } 41 | 42 | if temp_type.eq("2") { 43 | println! ("请输入要转换的法氏温度:"); 44 | let temp = get_temp_input(); 45 | 46 | println! ("法氏温度:{:.2}°F,约为摄氏温度:{:.2}°C", temp, fah_to_cels(temp)); 47 | } 48 | } 49 | } 50 | 51 | fn get_temp_input() -> f32 { 52 | return loop { 53 | let mut tmp = String::new(); 54 | 55 | io::stdin() 56 | .read_line(&mut tmp) 57 | .expect("读取输入失败"); 58 | 59 | match tmp.trim().parse() { 60 | Ok(num) => { break num }, 61 | Err(_) => { 62 | println! ("请输入一个浮点数,比如 -10.0, 15.6"); 63 | continue 64 | } 65 | }; 66 | }; 67 | } 68 | -------------------------------------------------------------------------------- /src/packages_crates_and_modules/packages_and_crates.md: -------------------------------------------------------------------------------- 1 | # 包与代码箱 2 | 3 | **Packages and Crates** 4 | 5 | 6 | 我们要介绍的模组系统头两个部分,分别是代码包与代码箱。 7 | 8 | *代码箱,crate* 是 Rust 编译器一次要考虑的最小代码量。即使咱们运行的是 `rustc` 而不是 `cargo`,并只传递了一个源代码文件(就像我们在第 1 章 “编写和运行 Rust 程序” 小节中所做的那样),编译器也会将该文件,视为一个代码箱。代码箱可以包含模组,模组也可以定义在与该代码箱一起编译的其他文件中,正如我们将在接下来的小节中看到的那样。 9 | 10 | 代码箱有两种形式:二进制代码箱或库代码箱。*二进制代码箱,binary crates* 属于可以编译成咱们可以运行的可执行文件的程序,例如命令行程序或服务器。每个二进制代码箱,都必须有个名为 `main` 的函数,定义出可执行文件运行时会发生什么。到目前为止,我们创建的所有代码箱,都是二进制代码箱。 11 | 12 | *库代码箱,library crates* 没有 `main` 函数,也不会编译成可执行文件。相反,他们定义了旨在与多个项目共享的功能。例如,我们在 [第 2 章](../Ch02_Programming_a_Guessing_Game.md#生成随机数) 中,使用的 `rand` 代码箱,就提供了生成随机数的功能。大多数时候,当 Rustaceans 说 “代码箱,crate” 时,他们指的是库代码箱,而且他们会将 “代码箱”,与一般的编程概念 “库,library” 互换使用。 13 | 14 | 而 *代码箱根,crate root*,则是个 Rust 编译器开始之处的源代码文件,并构成了咱们代码箱的 *根模组,root module*(我们将在 [定义控制作用域和隐私的模组](/packages_crates_and_modules/defining_modules.md) 小节,深入探讨模组)。 15 | 16 | *包,package* 是提供了一组功能的一或多个代码箱的捆绑。包会包含一个描述如何构建这些代码箱的 `Cargo.toml` 文件。Cargo 实际上就是个包含了,咱们用来构建代码的命令行工具的包。Cargo 包还包含该二进制代码箱所依赖的库代码箱。其他项目可以依赖于 Cargo 的库代码箱,使用与 Cargo 这个命令行工具,所使用的同样逻辑。 17 | 18 | 一个包可以包含任意数量的二进制代码箱,但最多只能包含一个库代码箱。一个包必须至少包含一个代码箱,无论是库代码箱,还是二进制代码箱。 19 | 20 | 我们来看看,在我们创建某个软件包时,会发生什么。首先,我们输入命令 `cargo new`: 21 | 22 | 23 | ```console 24 | $ cargo new my-project --vcs=none 25 | Created binary (application) `my-project` package 26 | $ ls my-project 27 | Cargo.toml src 28 | $ ls my-project/src 29 | main.rs 30 | ``` 31 | 32 | 33 | 运行 `cargo new` 后,我们使用 `ls` 查看 Cargo 创建了什么。在该项目目录中,有个 `Cargo.toml` 文件,给到我们一个包。还有个包含了 `main.rs` 的 `src` 目录。请用咱们的文本编辑器,打开 `Cargo.toml`,注意其中没有提到 `src/main.rs`。Cargo 遵循,`src/main.rs` 是与该软件包同名的二进制代码箱的代码箱根,这一惯例。同样,Cargo 知道,如果包目录中包含 `src/lib.rs`,那么该包中就包含一个,与该包同名的库代码箱,而 `src/lib.rs` 就是其代码箱根。Cargo 会将代码箱根文件,传递给 `rustc` 以构建出该库或二进制程序。 34 | 35 | 这里,我们有着一个只包含 `src/main.rs` 的包,意味着他只包含一个名为 `my-project` 的二进制代码箱。如果某个包包含 `src/main.rs` 和 `src/lib.rs`,那么他就有两个代码箱:一个二进制代码箱和一个库代码箱,且两个代码箱都有着与该包同样的名字。通过在 `src/bin` 目录中放置一些文件,包可以有多个二进制代码箱:每个文件都将是个单独的二进制代码箱。 36 | 37 | 38 | (End) 39 | 40 | 41 | -------------------------------------------------------------------------------- /projects/limit_tracker/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub trait Messenger { 2 | fn send(&self, msg: &str); 3 | } 4 | 5 | pub struct LimitTracker<'a, T: Messenger> { 6 | messenger: &'a T, 7 | value: usize, 8 | max: usize, 9 | } 10 | 11 | impl<'a, T> LimitTracker<'a, T> 12 | where 13 | T: Messenger, 14 | { 15 | pub fn new(messenger: &'a T, max: usize) -> LimitTracker<'a, T> { 16 | LimitTracker { 17 | messenger, 18 | value: 0, 19 | max, 20 | } 21 | } 22 | 23 | pub fn set_value(&mut self, value: usize) { 24 | self.value = value; 25 | 26 | let percentage_of_max = self.value as f64 / self.max as f64; 27 | 28 | match percentage_of_max { 29 | p if p >= 1.0 => self.messenger.send("出错:你已超出你的配额!"), 30 | p if p >= 0.9 => self.messenger.send("紧急警告:你已用掉你配额的 90% !"), 31 | p if p >= 0.75 => self.messenger.send("警告:你已用掉你配额的 75% !"), 32 | _ => {}, 33 | } 34 | } 35 | } 36 | 37 | #[cfg(test)] 38 | mod tests { 39 | use super::*; 40 | use std::cell::RefCell; 41 | 42 | struct MockMessenger { 43 | sent_messages: RefCell>, 44 | } 45 | 46 | impl MockMessenger { 47 | fn new() -> MockMessenger { 48 | MockMessenger { 49 | sent_messages: RefCell::new(vec! []), 50 | } 51 | } 52 | } 53 | 54 | impl Messenger for MockMessenger { 55 | fn send(&self, message: &str) { 56 | self.sent_messages.borrow_mut().push(String::from(message)); 57 | } 58 | } 59 | 60 | #[test] 61 | fn it_sends_an_over_75_percent_waring_message() { 62 | let mock_messenger = MockMessenger::new(); 63 | let mut limit_tracker = LimitTracker::new(&mock_messenger, 100); 64 | 65 | limit_tracker.set_value(80); 66 | println! ("{}", mock_messenger.sent_messages.borrow().iter().next().unwrap()); 67 | 68 | assert_eq! (mock_messenger.sent_messages.borrow().len(), 1); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /projects/simple_blog/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | #![allow(unused_variables)] 3 | 4 | pub struct Post { 5 | state: Option>, 6 | content: String, 7 | } 8 | 9 | impl Post { 10 | pub fn new() -> Post { 11 | Post { 12 | state: Some(Box::new(Draft {})), 13 | content: String::new(), 14 | } 15 | } 16 | 17 | pub fn add_text(&mut self, text: &str) { 18 | self.content.push_str(text); 19 | } 20 | 21 | pub fn content(&self) -> &str { 22 | self.state.as_ref().unwrap().content(self) 23 | } 24 | 25 | pub fn request_review(&mut self) { 26 | if let Some(s) = self.state.take() { 27 | self.state = Some(s.request_review()) 28 | } 29 | } 30 | 31 | pub fn approve(&mut self) { 32 | if let Some(s) = self.state.take() { 33 | self.state = Some(s.approve()) 34 | } 35 | } 36 | } 37 | 38 | trait State { 39 | fn request_review(self: Box) -> Box; 40 | fn approve(self: Box) -> Box; 41 | fn content<'a>(&self, post: &'a Post) -> &'a str { "" } 42 | } 43 | 44 | struct Draft {} 45 | 46 | impl State for Draft { 47 | fn request_review(self: Box) -> Box { 48 | Box::new(PendingReview {}) 49 | } 50 | 51 | fn approve(self: Box) -> Box { 52 | self 53 | } 54 | } 55 | 56 | struct PendingReview {} 57 | 58 | impl State for PendingReview { 59 | fn request_review(self: Box) -> Box { 60 | self 61 | } 62 | 63 | fn approve(self: Box) -> Box { 64 | Box::new(Published {}) 65 | } 66 | } 67 | 68 | struct Published {} 69 | 70 | impl State for Published { 71 | fn request_review(self: Box) -> Box { 72 | self 73 | } 74 | 75 | fn approve(self: Box) -> Box { 76 | self 77 | } 78 | 79 | fn content<'a>(&self, post: &'a Post) -> &'a str { 80 | &post.content 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/io_project/reading_a_file.md: -------------------------------------------------------------------------------- 1 | ## 读取文件 2 | 3 | 现在就要添加读取那个在 `file_path` 参数中所指定文件的功能了。首先,这里需要一个样本文件来对其进行测试:这里将使用一个有着少量文字、其中多个行均有一些重复文字的文件。下面清单 12-3 这首 Emily Dickinson 的诗歌用起来就会不错!在项目的根目录处创建一个叫做 `poem.txt` 的文件,并敲入这首 “I'm Nobody! Who are you?” 的诗歌。 4 | 5 | 文件名:`poem.txt` 6 | 7 | ```txt 8 | I'm nobody! Who are you? 9 | Are you nobody, too? 10 | Then there's a pair of us - don't tell! 11 | They'd banish us, you know. 12 | 13 | How dreary to be somebody! 14 | How public, like a frog 15 | To tell your name the livelong day 16 | To an admiring bog! 17 | ``` 18 | 19 | *清单 12-3:一首 Emily Dickinson 的诗歌成就了一个良好的测试用例* 20 | 21 | 22 | 有了这个文本后,就要编辑 `src/main.rs` 并添加读取该文件的代码了,如下清单 12-4 中所示。 23 | 24 | 文件名:`src/main.rs` 25 | 26 | ```rust 27 | use std::env; 28 | use std::fs; 29 | 30 | fn main() { 31 | // --跳过代码-- 32 | println! ("在文件 {} 中检索:{}", file_path, query); 33 | 34 | let contents = fs::read_to_string(file_path) 35 | .expect("应能读取这个这个文件"); 36 | 37 | println! ("有着文本:\n{}", contents); 38 | } 39 | ``` 40 | 41 | *清单 12-4:对由第二个参数所指定的文件内容进行读取* 42 | 43 | 首先,这里使用了一个 `use` 语句,将标准库的一个相对部分(a relevant part)带入进来:这里需要 `std::fs` 来对文件进行处理。 44 | 45 | 在 `main` 函数中,那个新的 `fs::read_to_string` 取了其中的 `file_path` 做参数,打开那个文件,并返回一个该文件内容的 `std::io::Result` 类型值。 46 | 47 | 在那之后,这里再次添加了一个临时的、于该文件被读取之后打印 `contents` 值的 `println!` 语句,因此这里就该程序到此在运行而进行检查了。 48 | 49 | 下面就来以任意字符串作为第一个参数(由于这里尚未实现检索的部分),并以那个 `poem.txt` 文件作为第二个参数,运行这段代码: 50 | 51 | ```rust 52 | $ cargo run -- the poem.txt lennyp@vm-manjaro 53 | Compiling minigrep v0.1.0 (/home/lennyp/rust-lang/minigrep) 54 | Finished dev [unoptimized + debuginfo] target(s) in 0.36s 55 | Running `target/debug/minigrep the poem.txt` 56 | 在文件 poem.txt 中检索:the 57 | 有着文本: 58 | I'm nobody! Who are you? 59 | Are you nobody, too? 60 | Then there's a pair of us - don't tell! 61 | They'd banish us, you know. 62 | 63 | How dreary to be somebody! 64 | How public, like a frog 65 | To tell your name the livelong day 66 | To an admiring bog! 67 | 68 | ``` 69 | 70 | 很好!这代码就读取并于随后打印出了那个文件的内容。但这代码有着少数几个缺陷。此时的这个 `main` 函数,有着多重义务:一般来讲,在每个函数只负责一件事情时,那么他们就是些更为清晰明了,并更易于维护的函数了。另一问题则是这里没有尽可能地对错误进行处理。这个程序还很小,因此这些缺陷就不是什么大问题,不过随着程序变大,就会变得更加难于彻底修复这些缺陷。在开发某个程序时,由于重构数量较少的代码要容易得多,因此尽早开始重构,是一种良好实践。接下来就会干这件事 -- 重构。 71 | 72 | 73 | (End) 74 | 75 | 76 | -------------------------------------------------------------------------------- /projects/hello/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | sync::{mpsc, Arc, Mutex}, 3 | thread, 4 | }; 5 | 6 | pub struct ThreadPool { 7 | workers: Vec, 8 | sender: Option>, 9 | } 10 | 11 | type Job = Box; 12 | 13 | impl ThreadPool { 14 | /// 创建出一个新的 ThreadPool。 15 | /// 16 | /// 其中的 size 为线程池中线程的数目。 17 | /// 18 | /// # 终止运行 19 | /// 20 | /// 这个 `new` 函数将在 size 为零时终止运行。 21 | pub fn new(size: usize) -> ThreadPool { 22 | assert! (size > 0); 23 | 24 | let (sender, receiver) = mpsc::channel(); 25 | 26 | let receiver = Arc::new(Mutex::new(receiver)); 27 | 28 | let mut workers = Vec::with_capacity(size); 29 | 30 | for id in 0..size { 31 | workers.push(Worker::new(id, Arc::clone(&receiver))); 32 | } 33 | 34 | ThreadPool { 35 | workers, 36 | sender: Some(sender), 37 | } 38 | } 39 | 40 | pub fn execute(&self, f: F) 41 | where 42 | F: FnOnce() + Send + 'static, 43 | { 44 | let job = Box::new(f); 45 | 46 | self.sender.as_ref().unwrap().send(job).unwrap(); 47 | } 48 | } 49 | 50 | impl Drop for ThreadPool { 51 | fn drop(&mut self) { 52 | drop(self.sender.take()); 53 | 54 | for worker in &mut self.workers { 55 | println! ("关闭 worker {}", worker.id); 56 | 57 | if let Some(thread) = worker.thread.take() { 58 | thread.join().unwrap(); 59 | } 60 | } 61 | } 62 | } 63 | 64 | struct Worker { 65 | id: usize, 66 | thread: Option>, 67 | } 68 | 69 | impl Worker { 70 | fn new(id: usize, receiver: Arc>>) -> Worker { 71 | let thread = thread::spawn(move || loop { 72 | let message = receiver.lock().unwrap().recv(); 73 | 74 | match message { 75 | Ok(job) => { 76 | println! ("Worker {id} 获取到一项作业;执行中。"); 77 | 78 | job(); 79 | } 80 | Err(_) => { 81 | println! ("Worker {id} 已断开链接;关闭中。"); 82 | break; 83 | } 84 | } 85 | }); 86 | 87 | Worker { 88 | id, 89 | thread: Some(thread), 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/concurrency/extensible_concurrency.md: -------------------------------------------------------------------------------- 1 | # `Sync` 与 `Send` 两个特质下的可扩展并发 2 | 3 | **Extensible Concurrency with the `Sync` and `Send` Traits** 4 | 5 | 6 | 有趣的是,Rust 语言并发方面的特性 *非常* 少。本章中到目前为止咱们讲到过的每种并发特性,都已是标准库而非语言本身的一部分。用于处理并发问题的选项,并不局限于这门语言或标准库;咱们可以编写自己的并发特性,或可以使用由其他人编写的并发特性。 7 | 8 | 不过,在这门语言中,是嵌入了两个并发概念的:即 `std::marker` 特质 `Sync` 与 `Send`。 9 | 10 | 11 | ## 使用 `Send` 特质实现线程间所有权转移 12 | 13 | **Allowing Transference of Ownership Between Threads with `Send`** 14 | 15 | 16 | 这个 `Send` 标识符特质,表示实现 `Send` 类型值的所有权,可以在线程间转移。几乎全部 Rust 类型都是 `Send` 类型,但有一些例外,包括 `Rc`:由于在咱们克隆了某个 `Rc` 并尝试将这份克隆的所有权,转移到另一线程时,两个现场可能在同一时间更新引用计数,因此 `Rc` 就不能是 `Send` 类型。由于这个原因,`Rc` 正是为其间咱们不打算付出线程安全方面性能开销的那些单线程情形,而实现的。 17 | 18 | 由此,Rust 的类型系统与特质边界,type system and trait bounds,就确保了咱们绝不会意外地将某个 `Rc`,不安全地跨越线程发送。当咱们在清单 16-14 中尝试这样做时,咱们就曾得到编译器报错 `` the trait `Send` is not implemented for `Rc>` ``。而在咱们切换到 `Arc` 这种 `Send` 类型时,那段代码就编译了。 19 | 20 | 由全部 `Send` 类型所组成的类型,也会被自动标记为 `Send` 类型。除开那些原始指针,raw pointers 外,那么可以说几乎全部原生类型都是 `Send` 的,咱们将在第 19 章中,讲到那些原始指针。 21 | 22 | 23 | ## 使用 `Sync` 实现来自多个线程的访问 24 | 25 | **Allowing Access from Multiple Threads with `Sync`** 26 | 27 | `Sync` 标识符表示实现 `Sync` 特质的类型,其被从多个线程引用是安全的。换句话说,任何类型 `T` 在 `&T` (即到 `T` 的不可变引用) 为 `Send` 的时,那么其即为 `Sync` 的,表示该引用可以安全地发送到另一线程。与 `Send` 类似,原生类型均为 `Sync` 的,且由全部都是 `Sync` 的类型所组成的类型,也都是 `Sync` 的。 28 | 29 | 灵巧指针 `Rc` 因为其不是 `Send` 的同样原因,其也不是 `Sync` 的。`RefCell` 类型(咱们曾在第 15 章讲过)以及相关的 `Cell` 类型家族,都不是 `Sync` 的。`RefCell` 在运行时所完成的借用检查实现,不是线程安全的。灵巧指针 `Mutex` 是 `Sync` 的,并正如咱们在 [于多个线程间共用 `Mutex`](#在多个线程间共用-mutext) 小节中看到的,其可被用于多个线程下共用访问。 30 | 31 | 32 | ## 手动实现 `Send` 与 `Sync` 是不安全的 33 | 34 | **Implementing `Send` and `Sync` Manually Is Unsafe** 35 | 36 | 37 | 由于 `Send` 与 `Sync` 特质构成的类型自动也是 `Send` 与 `Sync` 的,因此咱们大可不必手动实现这两个特质。而作为标记性特质,二者甚至都没有任何要实现的方法。他们只是在执行与并发性有关的不变性方面很有用。 38 | 39 | 手动实现这两个特质,涉及到实现一些不安全 Rust 代码,unsafe Rust code。在第 19 章咱们将讲到运用不安全 Rust 代码;至于现在,要点在于构造不是由一些 `Send` 与 `Sync` 部分组成的新并发类型,需要深思熟虑来维持那些安全保证。[The Rustonomicon](https://doc.rust-lang.org/nomicon/index.html) 有着这些保证的更多信息,以及维持这些保证的方式。 40 | 41 | 42 | # 本章小节 43 | 44 | 这不会是你在本书中将见到并发的最后一章:第 20 张中的那个项目,就将在相比于这里所讨论过较小示例,而更具现实意义的情形下用到本章中的那些概念。 45 | 46 | 正如早先所提到的,由于只有极少量的 Rust 处理并发方式,属于这门语言的一部分,因此许多并发解决方案,都是作为代码箱实现的。这些方案相比标准库进化更为迅速,那么就要确保在线搜寻当前的、最前沿代码箱,来用于多线程情形中。 47 | 48 | Rust 标准库提供了用于消息传递的信道,以及诸如 `Mutex` 与 `Arc` 等安全用于并发情景中的一些灵巧指针类型。类型系统与借用检查器,会确保应用了这些方案的代码,不会以数据竞争或无效引用结束。一旦让代码编译了,咱们就可以放下心来,代码将愉快地运行于多线程之上,而不会有在其他语言中常见的那些难于追踪的问题。并发编程自此不再是令人害怕的概念:去吧,让你的程序并发起来,无所畏惧! 49 | 50 | 接下来,咱们将讲到,随着咱们的 Rust 程序变得大了起来,建模问题与架构出方案的一些管用做法。此外,咱们将讨论 Rust 的一些习惯说法,这些说法可能与面向对象编程中所熟悉的有关。 51 | 52 | 53 | (End) 54 | 55 | 56 | -------------------------------------------------------------------------------- /theme/pagetoc.js: -------------------------------------------------------------------------------- 1 | // Un-active everything when you click it 2 | Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { 3 | el.addEventHandler("click", function() { 4 | Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { 5 | el.classList.remove("active"); 6 | }); 7 | el.classList.add("active"); 8 | }); 9 | }); 10 | 11 | var updateFunction = function() { 12 | 13 | var id; 14 | var elements = document.getElementsByClassName("header"); 15 | Array.prototype.forEach.call(elements, function(el) { 16 | if (window.pageYOffset >= el.offsetTop) { 17 | id = el; 18 | } 19 | }); 20 | 21 | Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { 22 | el.classList.remove("active"); 23 | }); 24 | if (!id) return; 25 | Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { 26 | if (id.href.localeCompare(el.href) == 0) { 27 | el.classList.add("active"); 28 | } 29 | }); 30 | }; 31 | 32 | // Populate sidebar on load 33 | window.addEventListener('load', function() { 34 | var pagetoc = document.getElementsByClassName("pagetoc")[0]; 35 | var elements = document.getElementsByClassName("header"); 36 | Array.prototype.forEach.call(elements, function (el) { 37 | var link = document.createElement("a"); 38 | link.appendChild(document.createTextNode(el.text)); 39 | link.href = el.href; 40 | link.classList.add("pagetoc-" + el.parentElement.tagName); 41 | pagetoc.appendChild(link); 42 | }); 43 | updateFunction.call(); 44 | }); 45 | 46 | 47 | 48 | // Handle active elements on scroll 49 | window.addEventListener("scroll", updateFunction); 50 | 51 | if(document.querySelector("#document-not-found404")) { 52 | let timeLeft = 10; 53 | 54 | var timerId = setInterval(() => { 55 | if(timeLeft == -1) { 56 | clearTimeout(timerId); 57 | let siteRoot = window.location.origin; 58 | window.location.replace(siteRoot); 59 | } else { 60 | let secCounts = document.querySelectorAll(".sec-count") 61 | secCounts.forEach(count => { 62 | count.innerHTML = timeLeft; 63 | }); 64 | timeLeft--; 65 | } 66 | }, 1000); 67 | } 68 | 69 | var f = document.getElementById("last-change"); 70 | if (f) { 71 | var text = f.innerHTML; 72 | text = text.replace("Last change", "知识共享许可协议,CC - 最后修改") 73 | text = text.replace("commit", "于提交") 74 | 75 | f.innerHTML = text 76 | } 77 | -------------------------------------------------------------------------------- /src/functional_features/performance.md: -------------------------------------------------------------------------------- 1 | # 性能比较:循环与迭代器 2 | 3 | **Comparing Performance: Loops vs. Iterators** 4 | 5 | 6 | 为确定是使用循环还是迭代器,咱们需要知道哪种实现更快:带有显式 `for` 循环的 `search` 函数版本,还带有迭代器的版本。 7 | 8 | 我们通过将阿瑟-柯南-道尔爵士的《福尔摩斯历险记》的全部内容加载到一个字符串中,并在内容中寻找单词 "福尔摩斯",进行了一次基准测试。下面是使用 `for` 循环的 `search` 版本和使用迭代器的版本的基准测试结果: 9 | 10 | ```console 11 | test bench_search_for ... bench: 19,620,300 ns/iter (+/- 915,700) 12 | test bench_search_iter ... bench: 19,234,900 ns/iter (+/- 657,200) 13 | ``` 14 | 15 | 迭代器的版本稍微快了一些!由我们不会在这里解释基准代码,因为重点不是要证明这两个版本是等价的,而是要了解这两种实现在性能上的总体比较。 16 | 17 | 为了获得更全面的基准,你应该用各种大小的文本作为 `contents`,用不同的词和不同长度的词作为 `query`,以及其他各种变化来检查。重点是:迭代器虽然是个高级的抽象概念,但被编译成的代码与咱们自己编写的低级代码大致相同。迭代器是 Rust 的 *零成本抽象,zero-cost abstractions* 之一,我们的意思是使用该抽象不会带来额外的运行时开销。这类似于 C++ 最初的设计者和实现者 Bjarne Stroustrup 在《C++ 基础》(2012)中对零开销的定义: 18 | 19 | > 一般来说,C++ 的实现遵循零开销原则:咱们不使用的东西,咱们不需要付出开销。再进一步:咱们使用的东西,咱们不可能手写出更良好的代码,the zero-overhead principle: What you don't use, you don't pay for. And further: What you do use, you couldn't hand code any better。 20 | 21 | 作为另一个示例,以下代码取自某个音频解码器。解码算法使用线性预测的数学运算,根据之前样本的线性函数来估计后面的数值。此代码使用迭代器链,an iterator chain,对作用域中三个变量执行一些数学计算:由一些数据构成 `buffer` 切片,由 12 个 `coeffecients` 构成的一个数组,以及保存着数据偏移量的 `qlp_shift`。咱们已在这个示例中声明了变量,但并未给他们任何值;尽管此代码在其上下文之外没有什么意义,但他仍不失为说明 Rust 如何将高级别的概念,转化为低级别代码的一个简练、真实的示例。 22 | 23 | ```rust 24 | let buffer: &mut [i32]; 25 | let coefficients: [i64; 12]; 26 | let qlp_shift: i16; 27 | 28 | for i in 12..buffer.len() { 29 | let prediction = coefficients.iter() 30 | .zip(&buffer[i - 12..i]) 31 | .map(|&c, &s| c * s as i64) 32 | .sum::() >> qlp_shift; 33 | let delta = buffer[i]; 34 | buffer[i] = prediction as i32 + delta; 35 | } 36 | ``` 37 | 38 | 为了计算预测值,此代码遍历 `coefficients` 中 12 个值中的每一个,并使用 `zip` 方法将系数值与 `buffer` 中的前 12 个值配对。随后对每个数值对,咱们将数值相乘,对所有结果求和,并将总和中的二进制位,向右偏移 `qlp_shift` 位。 39 | 40 | 像是音频解码器这样的应用中的计算,通常最优先考虑的是性能。在这里,我们正在创建一个迭代器,使用两个适配器,然后消费这个值。这段 Rust 代码会编译成什么汇编代码呢?好吧,在写这篇文章时,他可以编译成与咱们用手写的相同汇编代码。在系数的迭代过程中完全没有对应的循环: Rust 知道有 12 个迭代,所以他 “展开” 了这个循环。所谓 “展开,unrolling”,是消除循环控制代码方面的开销,而代之以生成循环历次迭代的重复代码的一种优化,*unrolling* is an optimization that removes the overhead of the loop controlling code and instead generates repetitive code for each iteration of the loop。 41 | 42 | 所有的系数都被存储在寄存器中,这意味着访问这些值的速度非常快。在运行时,对数组的访问没有边界检查。Rust 能够应用的所有这些优化使得所产生的代码非常高效。现在咱们知道了这些,咱们就可以毫无顾忌地使用迭代器和闭包了!他们使代码看起来更高级,但不会因为这样做而带来运行时的性能损失。 43 | 44 | 45 | 46 | # 本章小结 47 | 48 | 闭包与迭代器,是 Rust 受函数式编程概念启发的两项特性。他们有助于 Rust 以底层性能清楚表达高级别概念的能力。闭包与迭代器的实现,不会影响到运行时性能。这正是 Rust 致力于提供零成本抽象目标的一部分。 49 | 50 | 现在我们已经改进了 I/O 项目的表达能力,让我们再来看看 `cargo` 的更多特性,这些特性将帮助我们与世界分享这个项目。 51 | 52 | 53 | (End) 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/images/trpl17-05.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | 12 | %3 13 | 14 | 15 | 16 | fut1 17 | 18 | 19 | fut1 20 | 21 | ? 22 | 23 | ? 24 | 25 | ? 26 | 27 | 28 | 29 | fut2 30 | 31 | fut2 32 | 33 | 0 34 | 35 | 1 36 | 37 | 38 | 39 | 40 | 41 | fut2:c->fut1:c 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/io_project/std_err.md: -------------------------------------------------------------------------------- 1 | # 把错误消息写到标准错误而非标准输出 2 | 3 | **Writing Error Messages to Standard Error Instead of Standard Output** 4 | 5 | 6 | - 标准错误输出:standard error 7 | 8 | - 标准输出:standard output 9 | 10 | 到目前为止,咱们都是在把全部输出,使用那个 `println!` 宏输出到终端。而在绝大多数终端里,都有着两种类型的终端:用于通用信息的 *标准输出* ( *standard output*,`stdout`),及用于错误消息的 *标准错误* ( *standard error*,`stderr`)。这种区别,就可以让用户选择把程序的成功输出,导向某个文件,而仍把错误消息,打印到屏幕上。 11 | 12 | 那个 `println!` 宏,只能打印到标准输出,因此这里就不得不使用其他物件,来打印到标准错误了。 13 | 14 | 15 | ## 检视报错被写到何处 16 | 17 | **Checking Where Errors Are Written** 18 | 19 | 20 | 首先,我们来观察一下 `minigrep` 打印的内容,目前是如何写入标准输出的,包括我们想转而写入标准错误的任何错误信息。为此,我们将在有意引入一处错误的同时,把标准输出流重定向到某个文件。我们不会重定向标准错误流,因此发送到标准错误的任何内容,仍都将继续显示在屏幕上。 21 | 22 | 命令行程序预期会将错误信息,发送到标准错误流,因此即使我们将标准输出流,重定向到某个文件,也能在屏幕上看到错误信息。我们的程序目前表现不佳:我们将看到,他会将错误信息输出保存到某个文件中! 23 | 24 | 为演示这种行为,我们将以 `>` 和我们打算将标准输出流重定向到的文件 `output.txt` 路径,运行这个程序。我们将不传递任何参数,因为这会导致一个错误: 25 | 26 | ```console 27 | $ cargo run > output.txt 28 | ``` 29 | 30 | 其中的 `>` 语法,告诉 shell 将标准输出的内容,写入 `output.txt` 而非屏幕。我们没有看到,咱们所预期的错误信息,被打印在屏幕上,这就意味着他必定已经进入了那个文件。下面就是 `output.txt` 文件所包含的内容: 31 | 32 | 33 | ```txt 34 | 解析参数时遇到问题:未曾获取到查询字串 35 | ``` 36 | 37 | 没错,我们的错误信息,被打印到了标准输出。将这样的错误信息,打印到标准错误中,会更有用,这样只有成功运行的数据,才会出现在文件中。我们将改变这一点。 38 | 39 | 40 | ## 将错误信息打印到标准错误 41 | 42 | **Printing Errors to Standard Error** 43 | 44 | 我们将使用清单 12-24 中的代码,来更改错误信息的打印方式。由于本章前面的重构,所有打印错误信息的代码,都在 `main` 一个函数中。标准库提供了 `eprintln!` 这个,可以打印到标准错误流中的宏,因此咱们来将调用 `println!` 打印错误信息的两个地方,改为使用 `eprintln!`。 45 | 46 | 文件名:`src/main.rs` 47 | 48 | ```rust 49 | fn main() { 50 | let args: Vec = env::args().collect(); 51 | 52 | let config = Config::build(&args).unwrap_or_else(|err| { 53 | eprintln! ("解析参数时遇到问题:{err}"); 54 | process::exit(1); 55 | }); 56 | 57 | println! ("在文件 {} 中检索:{}", config.file_path, config.query); 58 | 59 | if let Err(e) = minigrep::run(config) { 60 | eprintln! ("应用程序错误:{e}"); 61 | process::exit(1); 62 | } 63 | } 64 | ``` 65 | 66 | *清单 12-24:使用 `eprintln!` 将错误消息写到标准错误而非标准输出* 67 | 68 | 咱们现在来以不带任何参数,并使用 `>` 重定向标准输出的同样方式,再度运行这个程序: 69 | 70 | ```console 71 | $ cargo run > output.txt  ✔ 72 | Compiling minigrep v0.1.0 (/home/peng/rust-lang/minigrep) 73 | Finished dev [unoptimized + debuginfo] target(s) in 0.49s 74 | Running `target/debug/minigrep` 75 | 解析参数时遇到问题:参数数量不足 76 | ``` 77 | 78 | 现在,我们在屏幕上看到了错误,而 `output.txt` 不包含任何内容,这正是我们所期望的命令行程序的行为。 79 | 80 | 咱们来以一些不会导致错误,但仍会将标准输出重定向到文件的参数,再度运行这个程序,就像这样: 81 | 82 | ```console 83 | $ cargo run -- to poem.txt > output.txt 84 | ``` 85 | 86 | 我们不会看到,任何到终端的输出,而 `output.txt` 将包含我们的结果: 87 | 88 | 文件名:`output.txt` 89 | 90 | ```plaintext 91 | 在文件 poem.txt 中检索:to 92 | Are you nobody, too? 93 | How dreary to be somebody! 94 | ``` 95 | 96 | 这表明我们现在,恰如其分的将标准输出,用于了成功的输出,而将标准错误,用于了错误输出。 97 | 98 | 99 | # 本章小节 100 | 101 | 本章回顾了到目前为止曾学过的一些主要概念,并涵盖了在 Rust 中怎样完成常见 I/O 操作。经由使用命令行参数、文件、环境变量,以及那个用于打印错误的 `eprintln!` 宏,现在就已准备好编写命令行应用程序了。结合先前那些章中的概念,咱们所编写的代码将是良好组织、以恰当数据结构有效地存储着数据、对错误加以优美地处理,并被妥善地测试过。 102 | 103 | 接下来,这里将探讨受函数式编程所影响的一些 Rust 特性:闭包与迭代器(closures and iterators)。 104 | 105 | 106 | (End) 107 | 108 | 109 | -------------------------------------------------------------------------------- /src/crates-io/cargo_install.md: -------------------------------------------------------------------------------- 1 | # 使用 `cargo install` 安装二进制代码箱 2 | 3 | **Installing Binaries with `cargo install`** 4 | 5 | 6 | `cargo install` 命令允许咱们在本地安装和使用二进制的代码箱。这并不是要取代系统包,system packages;它的目的是为 Rust 开发者提供一种方便的方式来安装别人在 [crates.io](https://crates.io) 上分享的工具。请注意咱们只能安装有二进制目标的包,packages that have binary targets。所谓 *二进制目标,binary target*,即与本身为非可运行,而适合于在其他程序中包含的库目标,a libary target,相反,因为代码箱有着一个 `src/main.rs` 文件,或有着被指定为二进制的另一文件时,而创建出的可以运行的程序。通常,代码箱会在 `README` 文件中,有着关于其是否为库代码箱,还是有着二进制目标,或二者皆具方面的信息。 7 | 8 | 使用 `cargo install` 安装的全部二进制程序文件,都被存储在安装根的 `bin` 文件中,in the installation root's `bin` folder。在使用 `rustup.rs` 安装 Rust,且没做任何定制配置时,这个目录将是 `$HOME/.cargo/bin`。为能运行咱们使用 `cargo install` 安装的程序,就要确保那个目录在 `$PATH` 中。 9 | 10 | > 注:可在任意位置运行 `cargo install` 命令,来安装 Crates.io 上的 Rust 二进制程序,这些程序都将被安装在 `$HOME/.cargo/bin` 下。若已安装了某个 Rust 程序后再安装他,那么就会有如下输出: 11 | 12 | ```console 13 | $ cargo install ripgrep 1m 4s lennyp@vm-manjaro 14 | Updating crates.io index 15 | Ignored package `ripgrep v13.0.0` is already installed, use --force to override 16 | ``` 17 | 18 | 比如,咱们曾在第 12 章中提到,有个用于搜索文件,`grep` 工具的 Rust 实现 `ripgrep`。要安装 `ripgrep`,咱们可运行如下命令: 19 | 20 | ```console 21 | $ cargo install ripgrep 22 | Updating crates.io index 23 | Installing ripgrep v13.0.0 24 | Compiling memchr v2.5.0 25 | Compiling cfg-if v1.0.0 26 | Compiling libc v0.2.137 27 | Compiling log v0.4.17 28 | Compiling proc-macro2 v1.0.47 29 | Compiling lazy_static v1.4.0 30 | Compiling regex-automata v0.1.10 31 | Compiling quote v1.0.21 32 | Compiling unicode-ident v1.0.5 33 | Compiling bstr v0.2.17 34 | Compiling syn v1.0.103 35 | Compiling aho-corasick v0.7.20 36 | Compiling regex-syntax v0.6.28 37 | Compiling serde_derive v1.0.147 38 | Compiling encoding_rs v0.8.31 39 | Compiling serde v1.0.147 40 | Compiling regex v1.7.0 41 | Compiling grep-matcher v0.1.5 42 | Compiling serde_json v1.0.89 43 | Compiling unicode-width v0.1.10 44 | Compiling fnv v1.0.7 45 | Compiling same-file v1.0.6 46 | Compiling once_cell v1.16.0 47 | Compiling thread_local v1.1.4 48 | Compiling globset v0.4.9 49 | Compiling textwrap v0.11.0 50 | Compiling encoding_rs_io v0.1.7 51 | Compiling memmap2 v0.5.8 52 | Compiling bitflags v1.3.2 53 | Compiling crossbeam-utils v0.8.14 54 | Compiling bytecount v0.6.3 55 | Compiling itoa v1.0.4 56 | Compiling ryu v1.0.11 57 | Compiling strsim v0.8.0 58 | Compiling termcolor v1.1.3 59 | Compiling clap v2.34.0 60 | Compiling grep-searcher v0.1.10 61 | Compiling atty v0.2.14 62 | Compiling base64 v0.13.1 63 | Compiling grep-printer v0.1.6 64 | Compiling grep-cli v0.1.6 65 | Compiling grep-regex v0.1.10 66 | Compiling ripgrep v13.0.0 67 | Compiling walkdir v2.3.2 68 | Compiling ignore v0.4.18 69 | Compiling grep v0.2.10 70 | Compiling num_cpus v1.14.0 71 | Finished release [optimized + debuginfo] target(s) in 1m 09s 72 | Installing /home/lennyp/.cargo/bin/rg 73 | Installed package `ripgrep v13.0.0` (executable `rg`) 74 | ``` 75 | 76 | 输出的倒数第二行显示出已安装二进制程序的位置与名字,在这个示例中名字便是 `rg`。正如前面提到的,只要安装目录是在 `$PATH` 中,随后咱们就可以运行 `rg --help`,并启动一个用于检索文件的更快、更具 Rust 风格的工具了! 77 | 78 | 79 | (End) 80 | 81 | 82 | -------------------------------------------------------------------------------- /src/images/15-01.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | %3 11 | 12 | 13 | 14 | table0 15 | 16 | Cons 17 | 18 | i32 19 | 20 | 21 | Cons 22 | 23 | i32 24 | 25 | 26 | Cons 27 | 28 | i32 29 | 30 | 31 | Cons 32 | 33 | i32 34 | 35 | 36 | Cons 37 | 38 | i32 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/packages_crates_and_modules/separating_modules.md: -------------------------------------------------------------------------------- 1 | # 将模组拆分为不同文件 2 | 3 | **Separating Modules into Different Files** 4 | 5 | 6 | 到目前为止,本章的所有示例都把多个模组,定义在一个文件中。当模组变大时,咱们就会想要把他们的定义,移入到单独文件中,这样代码更容易浏览。 7 | 8 | 例如,我们来从 [清单 7-17](./the_use_keyword.md#listing-7-17) 中,包含了多个餐厅模组的代码开始。我们将把这些模组提取到一些文件中,而不是把所有模组都定义在代码箱的根文件里。在本例中,代码箱的根文件为 `src/lib.rs`,但这一过程也适用于根文件为 `src/main.rs` 的二进制代码箱。 9 | 10 | 首先,我们将把 `front_of_house` 这个模组提取到他自己的文件中。请移除 `front_of_house` 模组的花括号内的代码,只留下 `mod front_of_house;` 这个声明,这样 `src/lib.rs` 文件就包含着下面清单 7-21 所示的代码。请注意,在创建出清单 7-22 中的 `src/front_of_house.rs` 文件前,这段代码将不会编译。 11 | 12 | 13 | 文件名:`src/lib.rs` 14 | 15 | ```rust 16 | mod front_of_house; 17 | 18 | pub use crate::front_of_house::hosting; 19 | 20 | pub fn eat_at_restaurant() { 21 | hosting::add_to_waitlist(); 22 | } 23 | ``` 24 | 25 | *清单 7-21:声明出其模组代码主体,将位于 `src/front_of_house.rs` 中的 `front_of_house` 模组* 26 | 27 | 接下来,将原先花括符中的代码,放入一个名为 `src/front_of_house.rs` 的新文件中,如下清单 7-22 所示。编译器之所以知道要在这个文件中查找,是因为他在代码箱根中,看到了名为 `front_of_house` 的模组声明。 28 | 29 | 30 | 文件名:`src/front_of_house.rs` 31 | 32 | ```rust 33 | pub mod hosting { 34 | pub fn add_to_waitlist() {} 35 | } 36 | ``` 37 | 38 | *清单 7-22:`src/front_of_house.rs` 中 `front_of_house` 模组内部的定义* 39 | 40 | 请注意,在咱们的模组树中,咱们只需使用 `mod` 声明加载某个文件 *一次*。一旦编译器知道了该文件是项目的一部分(且编译器会因咱们放置 `mod` 语句位置,而知道该代码位处模组树中何处),咱们项目中的其他文件,就应能使用 [“引用模组树中某个项目的路径”](./paths.md) 小节中介绍的到其声明处的路径,引用该加载文件的代码。换句话说,`mod` 并 *不是* 咱们在其他编程语言中,可能会看到的 “包含” 操作。 41 | 42 | 接下来,我们将把 `hosting` 模组提取到他自己的文件中。这个过程略有不同,因为 `hosting` 是 `front_of_house` 的一个子模组,而不是根模组。我们将把 `hosting` 的文件,放到一个模组树中的以其祖先命名的新目录中,在此情形下即为 `src/front_of_house`。 43 | 44 | 要开始迁移 `hosting`,我们就要将 `src/front_of_house.rs`,修改为只包含 `hosting` 模组的声明: 45 | 46 | 文件名:`src/front_of_house.rs` 47 | 48 | ```rust 49 | pub mod hosting; 50 | ``` 51 | 52 | 然后,我们创建一个 `src/front_of_house` 目录及一个存放 `hosting` 模组中所定义内容的 `hosting.rs` 文件: 53 | 54 | 文件名:`src/front_of_house/hosting.rs` 55 | 56 | ```rust 57 | pub fn add_to_waitlist() {} 58 | ``` 59 | 60 | 如果我们将 `hosting.rs` 文件放在 `src` 目录下,编译器就会期望 `hosting.rs` 的代码,属于在代码箱根中声明的 `hosting` 模组,而非作为 `front_of_house` 模组子模组声明的。确定哪些文件属于哪个模组代码的编译器规则,意味着目录和文件结构,会与模组树更加一致。 61 | 62 | > **备用文件路径** 63 | > 64 | > 到目前为止,我们已经介绍了 Rust 编译器所使用的最常见文件路径,但 Rust 还支持一种较旧的文件路径风格。对于代码箱根中声明的一个名为 `front_of_house` 模组,编译器将在以下位置查找该模组的代码: 65 | 66 | - `src/front_of_house.rs`(即这里讲到的); 67 | - `src/front_of_house/mod.rs`(较早样式,仍被支持的路径)。 68 | 69 | > 对于 `front_of_house` 子模组的一个名为 `hosting` 的模组,编译器将在以下位置查找该模组的代码: 70 | 71 | - `src/front_of_house/hosting.rs`(即这里讲到的); 72 | - `src/front_of_house/hosting/mod.rs`(较早样式,仍被支持的路径)。 73 | 74 | > 若咱们对同一模组同时使用这两种样式,咱们将得到一个编译器报错。在同一个项目中对不同模组混合使用这两种样式是允许的,但这可能会让浏览咱们项目的人感到困惑。 75 | > 76 | > 使用名为 `mod.rs` 文件样式的主要缺点,是咱们的项目可能会产生大量名为 `mod.rs` 的文件,当咱们在咱们的编辑器中同时打开这些文件时,这就可能造成混淆。 77 | 78 | 我们已将各个模组的代码移至独立文件中,同时模组树保持不变。`eat_at_restaurant` 中的函数调用,在无需任何修改下就将正常工作,尽管这些函数的定义现在位于别的文件中。随着模组规模扩大,这种技术允许咱们将其迁移至新文件。 79 | 80 | 请留意 `src/lib.rs` 中的 `pub use crate::front_of_house::hosting` 这个语句没有改变,且 `use` 语句对哪些文件被作为该代码箱的部分而被编译也没有任何影响。其中的 `mod` 关键字声明了这些模组,同时 Rust 会在与模组同名的文件中,查找要放入该模组的代码。 81 | 82 | 83 | # 本章小节 84 | 85 | Rust 允许咱们将包拆分为多个代码箱,并将代码箱拆分为模组,这样咱们就可以从一个模组,引用另一模组中所定义的那些项目。通过指定绝对路径或相对路径,咱们就可以做到这点。使用 `use` 语句,这些路径就被带入作用域,这样咱们就可以在该作用域中,对项目的多次引用使用一个更短的路径。模组代码默认是私有的,但咱们可通过添加 `pub` 关键字,将他们的定义构造为公开。 86 | 87 | 在下一章中,我们将探讨标准库中的一些集合数据结构,在咱们良好组织的代码中,咱们就可以使用这些集合数据结构。 88 | 89 | 90 | (End) 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/images/trpl17-08.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | 12 | cluster_deref 13 | 14 | String 15 | 16 | 17 | 18 | pinned_box 19 | 20 | Pin 21 | 22 | 23 | 24 | 25 | 26 | pin 27 | 28 | 29 | 30 | 31 | pinned_box:c->pin 32 | 33 | 34 | 35 | 36 | fut 37 | 38 | 5usize 39 | 40 | h 41 | 42 | e 43 | 44 | l 45 | 46 | l 47 | 48 | o 49 | 50 | 51 | 52 | pin->fut:target 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 57 | -------------------------------------------------------------------------------- /src/appendix/terminology_list.md: -------------------------------------------------------------------------------- 1 | # 附录 I - 术语清单 2 | 3 | 4 | - 命令行界面 5 | 6 | Command-Line Interface,在终端里运行的应用,与在 GUI 窗口中应用不同。 7 | 8 | - 模组系统 9 | 10 | The module system,大型程序中,组织代码的方式。 11 | 12 | 13 | - 迁移所有权 14 | 15 | 在闭包参数清单前,使用 `move` 关键字,让闭包取得其用到的所在环境中的值所有权。 16 | 17 | - 关联类型 18 | 19 | Associated type, 是通过 `type` 关键字,定义在特质下的类型。咱们知道方法即为关联函数,associated function,那么关联类型自然与关联函数有些类似。 20 | 21 | 22 | - 消费适配器 23 | 24 | Consuming adaptor, `Iterator` 特质上,会调用到迭代器 `next` 方法的一些方法,由于这些方法会耗尽迭代器,故他们被称为消费适配器。 25 | 26 | 27 | - 迭代器适配器 28 | 29 | Iterator adaptor,`Iterator` 特质上,通过改变原迭代器某些方面而产生出另一迭代器的一些方法。 30 | 31 | 32 | - 零成本抽象 33 | 34 | Zero-cost abstractions,相较于一般实现,语言提供的高级抽象在编译后生成的代码,与自己努力编写出的优化低级别代码类似。故使用高级抽象是没有运行时开销的。 35 | 36 | 37 | - 展开优化 38 | 39 | Unrolling,Rust 编译器在编译迭代器代码时,会把已知的历次迭代展开为重复代码,而实现性能优化。 40 | 41 | 42 | - 文档注释 43 | 44 | Documentation comment, 将产生出 HTML 的注释。 45 | 46 | 47 | - 重导出程序项目 48 | 49 | Re-export, 使用 `pub use` 重新导出程序项目。 50 | 51 | 52 | - 语义版本控制规则 53 | 54 | Semantic Versioning rules, 又大版本、小版本及补丁版本构成的,形如 `MAJOR.MINOR.PATCH` 的版本编号规则。参考:[semver.org](https://semver.org)。 55 | 56 | 57 | - 工作区 58 | 59 | Workspace,为有着多个库代码箱的大型项目组织的一项 Cargo 特性。 60 | 61 | 62 | - 编译出的物件 63 | 64 | The compiled artifacts 65 | 66 | 67 | - 路径依赖 68 | 69 | A path dependency 70 | 71 | 72 | - 匣子类型(数据结构) 73 | 74 | `Box`,由存储在栈上的指针,与存储在堆上的数据,实现的一种数据结构。 75 | 76 | 77 | - 间接 78 | 79 | Indirection, 匣子类型的变量,通过保存指向数据在内存堆上的地址,而间接保存了数据。 80 | 81 | 82 | - 解引用强制转换 83 | 84 | Deref coercion,类似于其他语言的开箱操作。 85 | 86 | 87 | - 元组结构体 88 | 89 | A tuple struct, 形式为 `struct MyBox(T)`,是保持着只有一个元素元组的结构体,`Box` 的数据结构为元组结构体。 90 | 91 | 92 | - 前奏 93 | 94 | The Rust Prelude, `std::prelude` 模组。前奏是 Rust 自动导入到每个 Rust 程序中的东西的列表。他被保持在尽可能小的范围内,并且专注于几乎每个 Rust 程序都会用到的东西,特别是特质。参见:[`std::prelude`](https://doc.rust-lang.org/std/prelude/index.html)。 95 | 96 | 97 | - 内部可变性模式 98 | 99 | The interior mutability pattern, Rust 的一种设计模式,用于改变不可变值内部的某个值。 100 | 101 | 102 | - 内存泄漏 103 | 104 | Memory leak, 出现未清理内存的情况。 105 | 106 | 107 | - 关联类型 108 | 109 | An associated type, 通过 `type Target = t;` 这种语法声明出的类型,是声明泛型参数的一种稍微不同的方式。 110 | 111 | 112 | - 单态化 113 | 114 | 所谓 *单态化,monomorphization*,是指即通过把在编译后用到的具体类型填入到泛型位置,而将通用代码转换为具体代码的过程。参考 [使用泛型代码的性能问题](Ch10_Generic_Types_Traits_and_Lifetimes.md#使用泛型参数代码的性能问题)。 115 | 116 | 117 | - 内聚属性 118 | 119 | a property called *coherence*,参见 [在类型上实现某个特质](Ch10_Generic_Types_Traits_and_Lifetimes.md#在类型上实现某个特质)。 120 | 121 | 122 | - 孤儿规则 123 | 124 | the orphan rule, 参见 [在类型上实现某个特质](Ch10_Generic_Types_Traits_and_Lifetimes.md#在类型上实现某个特质)。 125 | 126 | 127 | - `impl Trait` 语法 128 | 129 | `impl Trait` syntax, 在函数参数清单中,将特质用作参数类型注解的语法。参见:[作为参数的特质](Ch10_Generic_Types_Traits_and_Lifetimes.md#作为参数的特质) 130 | 131 | 132 | - 特质边界语法 133 | 134 | Trait bound syntax, 参见 [特质边界语法](Ch10_Generic_Types_Traits_and_Lifetimes.md#特质边界语法) 135 | 136 | 137 | - 语法糖 138 | 139 | Sugar syntax, 参见 [特质边界语法](Ch10_Generic_Types_Traits_and_Lifetimes.md#特质边界语法) 140 | 141 | 142 | - 指明多个特质边界的 `+` 语法 143 | 144 | The `+` syntax for specifying multiple trait bounds, 参见:[使用 + 语法,指定多个特质边界](Ch10_Generic_Types_Traits_and_Lifetimes.md#使用--语法指定多个特质边界) 145 | 146 | 147 | - `where` 子句 148 | 149 | `where` clauses, 参见 []() 150 | 151 | 152 | - 生命周期省略规则 153 | 154 | Lifetime elision rules, 编程到 Rust 引用分析中的一些确定性模式。 155 | 156 | 157 | - 输入生命周期 158 | 159 | Input lifetimes,函数或方法上的生命周期 160 | 161 | 162 | - 输出生命周期 163 | 164 | Output lifetimes, 返回值上的生命周期 165 | 166 | 167 | (End) 168 | 169 | 170 | -------------------------------------------------------------------------------- /src/appendix/keywords.md: -------------------------------------------------------------------------------- 1 | # 附录 A:关键字 2 | 3 | 以下清单包含了 Rust 语言当前或今后要用到的一些关键字。由此,他们便不能被用作标识符(除在 [“原始标识符”](#原始标识符) 小节中咱们将讨论的那些外)了。所谓标识符,是函数、变量、参数、结构体字段、模组、代码箱、常量、宏、静态值、属性、类型、特质或生命周期等的名字。 4 | 5 | 6 | ## 当前在用的关键字 7 | 8 | **Keywords Currently in Use** 9 | 10 | 11 | 下面是当前在用关键字的清单,带有其作用描述。 12 | 13 | - `as` - 执行原生强制转换,primitive casting,消除包含着某个项目的特定特质歧义,disambiguate the specific trait containing a item,或重命名 `use` 语句中的项目; 14 | - `async` - 返回一个 `Future` 类型值,而非阻塞当前线程; 15 | - `await` - 在某个 `Future` 值的结果准备好前,暂停程序执行; 16 | - `break` - 立即退出某个循环; 17 | - `const` - 定义出常量项目或常量原始指针; 18 | - `continue` - 继续下一循环迭代; 19 | - `crate` - 在模组路径中,指向代码箱根; 20 | - `dyn` - 动态调遣到某个特质对象,参考 [特质对象执行动态调遣](Ch17_Object_Oriented_Programming_Features_of_Rust.md#特质对象执行动态调遣); 21 | - `else` - `if` 的回退,及 `if let` 控制流的构件; 22 | - `extern` - 链接外部函数或变量; 23 | - `false` - 布尔值假的字面值; 24 | - `fn` - 定义出某个函数或函数指针类型; 25 | - `for` - 对某个迭代器的项目加以迭代、实现某个特质,或指明某个更高级别的生命周期,a higher-ranked lifetime; 26 | - `if` - 基于某个条件表达式结果的分支; 27 | - `impl` - 实现固有或特质功能,implement inherent or trait functionality; 28 | - `in` - `for` 循环语法的一部分; 29 | - `let` - 绑定某个变量; 30 | - `loop` - 无条件地循环; 31 | - `match` - 将某个值与模式匹配; 32 | - `mod` - 定义出模组; 33 | - `move` - 领导闭包取得其所有捕获值的所有权; 34 | - `mut` - 注解出引用、原始指针或模式绑定等中的可变性; 35 | - `pub` - 注解出结构体、`impl` 代码块或模组等中的公开可见性; 36 | - `ref` - 按引用绑定; 37 | - `return` - 自函数返回值; 38 | - `Self` - 咱们正定义或实现中类型的类型别名; 39 | - `self` - 方法主体,method subject,或当前模组; 40 | - `static` - 在整个程序执行过程持续有效的全局变量或生命周期; 41 | - `struct` - 定义出某个结构体; 42 | - `super` - 当前模组的父模组; 43 | - `trait` - 定义出某个特质; 44 | - `true` - 布尔值真的字面值; 45 | - `type` - 定义出某个类型别名或关联类型; 46 | - `union` - 定义出某个 [联合体](https://doc.rust-lang.org/reference/items/unions.html),是在联合体声明时用到的唯一关键字; 47 | - `unsafe` - 注解非安全代码、函数、特质或一些实现; 48 | - `use` - 将符号带入到作用域; 49 | - `where` - 注解约束某个类型的子句; 50 | - `while` - 基于某个表达式结果而有条件的循环。 51 | 52 | 53 | ## 为今后使用保留的关键字 54 | 55 | **Keywords Reserved for Future Use** 56 | 57 | 58 | 以下关键字尚无任何功能,但被 Rust 为今后的潜在使用而保留。 59 | 60 | - `abstract` 61 | - `become` 62 | - `box` 63 | - `do` 64 | - `final` 65 | - `macro` 66 | - `override` 67 | - `priv` 68 | - `try` 69 | - `typeof` 70 | - `unsized` 71 | - `virtual` 72 | - `yield` 73 | 74 | 75 | ## 原始标识符 76 | 77 | **Raw Identifiers** 78 | 79 | 80 | *原始标识符,raw identifiers* 属于允许实现使用一般不被允许关键字的语法。是通过在关键字前加上前缀 `r#`,使用原始标识符的。 81 | 82 | 比如,`match` 是个关键字。在咱们尝试编译下面这个使用 `match` 作其名字的函数时: 83 | 84 | 文件名:`src/main.rs` 85 | 86 | ```rust 87 | fn match(needle: &str, haystack: &str) -> bool { 88 | haystack.contains(needle) 89 | } 90 | ``` 91 | 92 | 咱们将得到这样的报错: 93 | 94 | ```console 95 | error: expected identifier, found keyword `match` 96 | --> src/main.rs:1:4 97 | | 98 | 1 | fn match(needle: &str, haystack: &str) -> bool { 99 | | ^^^^^ expected identifier, found keyword 100 | ``` 101 | 102 | 该报错显示咱们无法将关键字 `match` 用作函数标识符。要将 `match` 用作函数名字,咱们就需要使用原始标识符语法,像下面这样: 103 | 104 | 文件名:`src/main.rs` 105 | 106 | ```rust 107 | fn r#match(needle: &str, haystack: &str) -> bool { 108 | haystack.contains(needle) 109 | } 110 | 111 | fn main() { 112 | assert! (r#match("foo", "foobar")); 113 | } 114 | ``` 115 | 116 | 此代码将不带任何错误地编译。请注意那个函数的定义中,与 `main` 中该函数被调用处其名字上的 `r#` 前缀。 117 | 118 | 原始标识符实现了将任何咱们所选的词语用作标识符,即使那个词语碰巧是个保留的关键字。这给到咱们更自由地选择标识符名字,以及实现与一些以其中这些词语不属于关键字的语言,所编写的程序集成。此外,原始标识符实现了,对那些以不同于咱们代码箱 Rust 版本编写库加以运用。比如,在 2015 版中 `try` 就不是个关键字,但在 2018 版本中却是。若咱们依赖于一个使用 2015 版本编写的库,而该库有一个 `try` 函数,那么咱们就将需要在这种情况下,使用原始标识符 `r#try`,来从咱们的 2018 版本的代码,调用那个函数。请参阅 [附录 E](#appendix-e) 了解更多有关版本的信息。 119 | 120 | 121 | (End) 122 | 123 | 124 | -------------------------------------------------------------------------------- /src/Ch16_1_async_programming.md: -------------------------------------------------------------------------------- 1 | # 异步编程基础:异步、等待、未来值与流 2 | 3 | 许多我们要求计算机执行的操作,都需要一段时间才能完成。在等待这些长时间运行的进程完成时,若我们能做一些其他事情,那就再好不过了。现代计算机提供了两种同时处理多个操作的技术:并行机制与并发操作。不过,一旦我们开始编写那些涉及并行或并发操作的程序时,我们很快就会遇到 *异步编程* 所固有的一些新挑战,即操作可能无法按照他们启动的顺序,依次完成。本章建立在第 16 章中使用线程的并行机制,及通过引入另一种异步编程方法: Rust 的 Futures、流与支持他们的 `async` 和 `await` 语法,以及在异步操作间进行管理及协调的一些工具,实现的并发上。 4 | 5 | 6 | 我们来举个例子。假设咱们要导出一段家庭庆祝活动的视频,这个操作可能需要几分钟到几小时不等。视频导出将尽可能多地用到其做能使用的 CPU 和 GPU。如果咱们只有一个 CPU 内核,而咱们的操作系统在导出完成前,不会暂停该导出 -- 也就是说,如果他 *同步地* 执行该导出,那么在该任务运行期间,咱们就无法在咱们的计算机上做任何其他事情。这将是非常令人沮丧的经历。幸运的是,咱们电脑的操作系统可以,而且也确实经常隐蔽地中断该导出,让咱们可同时完成其他工作。 7 | 8 | 9 | 现在,假设咱们正下载某个别人共享的视频,这也需要一段时间,但不会占用那么多 CPU 时间。在这种情况下,CPU 必须等待数据自网络到达。虽然数据开始到达后咱们就可以开始读取,但可能需要一些时间才能全部显示出来。即使数据全部都有了,但如果视频相当大,那么加载数据也可能需要至少一两秒才能全部加载。这听起来可能不算什么,但对于每秒可以执行数十亿次运算的现代处理器来说,这已经是很长的时间了。同样,在等待网络调用结束时,咱们的操作系统会隐形地中断咱们的程序,允许 CPU 执行其他工作。 10 | 11 | 12 | 视频输出是个 *CPU 密集,CPU-bound* 或 *计算密集,compute-bound* 操作的例子。他受限于计算机 CPU 或 GPU 的潜在数据处理速度,以及能将多少速度用于该操作。而视频下载则是个 *IO 密集,IO-bound* 操作的例子,因为他受计算机 *输入及输出* 速度的限制;他只能以通过网络发送数据的速度运行。 13 | 14 | 15 | 在这两个例子中,操作系统的隐形中断,the operating system's invisible interrupts,均提供了某种形式的并发性。不过,这种并发只发生在整个程序的层面上:操作系统会中断某个程序,以让其他程序完成工作。在很多情况下,由于我们对咱们程序的掌握,要比操作系统更细粒度,因此我们可以发现操作系统所无法看到的并发机会。 16 | 17 | 18 | 例如,若我们正开发某个管理文件下载的工具,我们应能将咱们的程序,编写成启动一次下载不会锁定用户界面,且用户应能同时启动多个下载。不过,多数操作系统与网络交互的 API,却都是 *阻塞式的,blocking*;也就是说,他们会阻塞程序的进程,直到他们正处理的数据完全就绪。 19 | 20 | 21 | > 注意:仔细想想,这正是 *大多数* 函数调用的工作方式。不过,*阻塞* 一词通常保留给那些与文件、网络或计算机上其他资源交互的函数调用,因为在这些情况下,单个程序会从 *非阻塞,non-blocking* 的操作中受益。 22 | 23 | 24 | 通过生成一个专门下载各个文件的线程,我们可以避免阻塞咱们的主线程。不过,这些线程的开销,最终会成为问题。若调用一开始就不阻塞,那就更好了。此外,如果我们能采用与阻塞代码相同的直接写法,效果会更好,就像下面这样: 25 | 26 | 27 | ```rust 28 | let data = fetch_data_from(url).await; 29 | println!("{data}"); 30 | ``` 31 | 32 | 33 | 这正是 Rust 的 `async`(异步,*asynchronous* 的缩写)抽象所给到我们的。在本章中,咱们将学到有关 `async` 的所有知识,包括以下主题: 34 | 35 | 36 | - 怎样使用 Rust 的 `async` 与 `await` 语法; 37 | - 如何使用异步模型,解决我们在第 16 章中遇到的一些同样难题; 38 | - 多线程和异步如何提供,咱们可在许多情况下结合使用的互补方案。 39 | 40 | 41 | 不过,在了解异步在实际中的工作原理前,我们需要先绕道讨论一下并行和并发之间的区别,the difference between parallelism and concurrency。 42 | 43 | 44 | ## 并行与并发机制 45 | 46 | 47 | **Parrallelism and Concurrency** 48 | 49 | 50 | 到目前为止,我们都将并行和并发,看作是可以互换的。现在,我们需要更准确地区分他们,因为他们间的区别,会在我们开始工作时显现出来。 51 | 52 | 53 | 请设想某个团队在某个软件项目中,分工的不同方式。咱们可以给单个成员分配多项任务,也可以给每名成员分配一项任务,或者混合使用这两种方式。 54 | 55 | 56 | 当某单个成员在几项不同任务中的任何一项完成前,都工作于这些任务上时,这就是 *并发*。或许咱们在咱们电脑上,有着两个不同项目,当咱们在一个项目上感到无聊或卡住时,咱们就会切换到另一项目。咱们只是一个人,所以咱们无法同一时间在两项任务上取得进展,但咱们可以多任务处理,通过在两个任务之间切换,一次在一个任务上取得进展(见图 17-1)。 57 | 58 | 59 | ![并发工作流程,在任务 A 和任务 B 之间切换](./images/trpl17-01.svg) 60 | 61 | *图 17-1:一种并发工作流程,在任务 A 和任务 B 之间切换* 62 | 63 | 64 | 而在团队采取让每个成员单独完成某项任务方式,拆分一组任务时,这就是 *并行*。团队中的每个人,在同一时间团队中的每个人都能取得进展(见图 17-2)。 65 | 66 | 67 | ![并行工作流程,任务 A 和任务 B 的工作独立进行](./images/trpl17-02.svg) 68 | 69 | *图 17-2:一种并行工作流程,其中任务 A 和任务 B 上的工作独立进行* 70 | 71 | 72 | 在这两种工作流程中,咱们都可能需要协调不同任务。也许咱们 *会以为* 分配给某个人的任务,是完全独立于其他人工作的,但该任务实际上需要团队中另一人先完成他们的任务。有些工作可并行的完成,但有些工作实际上是 *串行的,serial*:其只能以序列方式进行,一项任务接着另一项任务,如图 17-3 所示。 73 | 74 | 75 | ![部分并行的工作流程,任务 A 和任务 B 的工作独立进行,直到任务 A3 被任务 B3 的结果阻断。](./images/trpl17-03.svg) 76 | 77 | *图 17-3:一种部分并行的工作流程,任务 A 与任务 B 的工作独立进行,直到任务 A3 被任务 B3 的结果阻塞* 78 | 79 | 80 | 同样,咱们也可能会发现,自己的一项任务依赖于另一项任务。现在,咱们的并行工作也变成串行的了。 81 | 82 | 83 | 84 | 并行与并发也会相互交叉。如果咱们得知某名同事在我们完成我们的某项任务前卡住了,咱们就可能会把所有精力都放在这项任务上,以 “解除” 该名同事的阻塞。这样,咱们和咱们的同事就无法再并行工作,咱们也无法再并发地执行咱们自己的任务。 85 | 86 | 软件和硬件的基本动态也是如此。在只有一个 CPU 核的机器上,CPU 一次只能执行一个操作,但其仍可并发地工作。利用线程、进程及异步等工具,计算机可暂停一项活动,并切换到其他活动,最后再次循环到第一项活动。在有着多个 CPU 核的机器上,计算机还可以并行工作。一个核心可以执行一项任务,而另一个核心可以执行完全无关的任务,这些操作实际上是在同一时间进行的。 87 | 88 | 89 | 在 Rust 中使用异步时,我们总是要处理并发问题。根据硬件、操作系统和我们所使用的异步运行时(稍后将详细介绍异步运行时),并发也可能在其表象之下,使用并行。 90 | 91 | 92 | 现在,我们来深入了解一下,Rust 中异步编程的工作原理。 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/patterns/refutability.md: -------------------------------------------------------------------------------- 1 | # 可证伪性:某个模式有无可能匹配失败 2 | 3 | **Refutability: Whether a Pattern Might Fail to Match** 4 | 5 | 6 | 模式有两种形式:可证伪与不可证伪的。将匹配所传递的任何可能值模式,即为 *不可证伪的,irrefuatable*。一个示例即为 `let x = 5;` 语句中的 `x`;由于 `x` 会匹配任何值,而因此必定不会匹配失败。那些对某些可能的值,会匹配失败的模式,便是 *可证伪的,refutable*。这样的一个示例,便是表达式 `if let Some(x) = a_value` 中的 `Some(x)`,因为若 `a_value` 中的值为 `None` 而非 `Some` 时,这个 `Some(x)` 模式就将不匹配。 7 | 8 | 函数参数、`let` 语句及 `for` 循环,就只能接受不可证伪的模式,这是由于这些情况下,当值不匹配时,程序便无法执行任何有意义的事情。`if let` 与 `while let` 表达式,接受可证伪与不可证伪的模式,但由于根据定义,他们被计划来处理可能的匹配失败:某个条件的功能,便在于其根据匹配成功或失败,而区别执行的能力,因此编译器会就不可证伪模式发出告警。 9 | 10 | 一般来说,咱们无须担心可证伪与不可证伪模式的区别;但是,咱们确实需要熟悉可证伪性的概念,这样咱们在看到报错消息时,就可以予以响应。在这些情形下,咱们将需要根据代码所预期的行为,而要么修改模式,或者修改该模式下用到的那个结构。 11 | 12 | 接下来就看看,当咱们在 Rust 要求使用不可证伪模式的地方,尝试使用某种可证伪模式,及反过来 Rust 要求使用可证伪模式,而尝试使用不可证伪模式时,会发生什么。下面清单 18-8 给出了一个 `let` 语句,不过咱们指定了一个可证伪的 `Some(x)` 模式。正如你会期待的那样,此代码将不会编译。 13 | 14 | ```rust 15 | let Some(x) = some_option_value; 16 | ``` 17 | 18 | *清单 18-*:在 `let` 下使用可证伪模式的尝试* 19 | 20 | 21 | 若 `some_option_value` 是个 `None` 值,他就会与模式 `Some(x)` 匹配失败,意味着该模式为可证伪的。但是,由于此处没有可处理 `None` 值的有效代码,因此该 `let` 表达式就只能接收某个不可证伪的模式。在编译时,Rust 将抱怨说咱们曾于要求不可证伪模式的某处,使用了可证伪模式: 22 | 23 | ```console 24 | $ cargo run 25 | Compiling patterns v0.1.0 (file:///projects/patterns) 26 | error[E0005]: refutable pattern in local binding: `None` not covered 27 | --> src/main.rs:3:9 28 | | 29 | 3 | let Some(x) = some_option_value; 30 | | ^^^^^^^ pattern `None` not covered 31 | | 32 | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant 33 | = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html 34 | note: `Option` defined here 35 | = note: the matched value is of type `Option` 36 | help: you might want to use `if let` to ignore the variant that isn't matched 37 | | 38 | 3 | let x = if let Some(x) = some_option_value { x } else { todo!() }; 39 | | ++++++++++ ++++++++++++++++++++++ 40 | 41 | For more information about this error, try `rustc --explain E0005`. 42 | error: could not compile `patterns` due to previous error 43 | ``` 44 | 45 | 由于咱们不曾以 `Some(x)` 涵盖(且无法涵盖到!)所以有效值,Rust 便理所当然地产生了一个编译器报错。 46 | 47 | 而当咱们在需要不可证伪模式处,有着某个可证伪模式时,咱们可通过修改用到该模式的代码修复之:与其使用 `let`,咱们可以使用 `if let`。随后在该模式不匹配时,该代码就仅仅会跳过位于那花括号中代码,从而给了其有效继续的一种方式。下面清单 18-9 给出了修复清单 18-8 中代码的方式。 48 | 49 | 50 | ```rust 51 | if let Some(x) = some_option_value { 52 | println! ("{}", x); 53 | } 54 | ``` 55 | 56 | *清单 18-9:使用 `if let` 与带有可证伪模式代码块,而非 `let`* 57 | 58 | 咱们就已给了代码一条出路了!这段代码是完全有效的,尽管其意味着咱们在不接收到报错下,无法使用某个不可证伪模式。而在咱们给到 `if let` 某个将始终匹配的模式时,如下清单 18-10 中所示,编译器就会给出一条告警。 59 | 60 | ```rust 61 | if let x = 5 { 62 | println! ("{}", x); 63 | } 64 | ``` 65 | 66 | *清单 18-10:在 `if let` 下使用不可证伪模式的尝试* 67 | 68 | Rust 会抱怨,以某个不可证伪模式使用 `if let` 没有意义: 69 | 70 | ```console 71 | $ cargo run lennyp@vm-manjaro 72 | Compiling refutable_demo v0.1.0 (/home/lennyp/rust-lang/refutable_demo) 73 | warning: irrefutable `if let` pattern 74 | --> src/main.rs:2:8 75 | | 76 | 2 | if let x = 5 { 77 | | ^^^^^^^^^ 78 | | 79 | = note: this pattern will always match, so the `if let` is useless 80 | = help: consider replacing the `if let` with a `let` 81 | = note: `#[warn(irrefutable_let_patterns)]` on by default 82 | 83 | warning: `refutable_demo` (bin "refutable_demo") generated 1 warning 84 | Finished dev [unoptimized + debuginfo] target(s) in 0.59s 85 | Running `target/debug/refutable_demo` 86 | 5 87 | ``` 88 | 89 | 由于这个原因,除了应以一个不可证伪模式匹配全部剩余值的最后支臂外,其他那些匹配支臂,就必须使用可证伪模式。Rust 允许咱们在仅有一个支臂的 `match` 中,使用不可证伪模式,但这种语法不是特别有用,并可以一个更简单的 `let` 语句替换。 90 | 91 | 现在,咱们就知道了哪些地方要使用模式,以及可证伪与不可证伪模式的区别,下面就来介绍所有可用于创建模式的语法。 92 | 93 | 94 | (End) 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/images/trpl17-06.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | 12 | cluster_box 13 | 14 | 15 | cluster_box_internal 16 | 17 | b1 18 | 19 | 20 | cluster_deref 21 | 22 | pinned 23 | 24 | 25 | 26 | pinned_box 27 | 28 | Pin 29 | 30 | 31 | 32 | 33 | 34 | pin 35 | 36 | 37 | 38 | 39 | pinned_box:c->pin 40 | 41 | 42 | 43 | 44 | box 45 | 46 | fut 47 | 48 | 0 49 | 50 | 51 | 52 | ... 53 | 54 | 1 55 | 56 | 57 | 58 | pin->box:target 59 | 60 | 61 | 62 | 63 | 64 | box:c->box:internal 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/images/rust-lang-ar21.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Ch10_Generic_Types_Traits_and_Lifetimes.md: -------------------------------------------------------------------------------- 1 | # 泛型、特质与生命周期 2 | 3 | 每种编程语言都有着用于有效处理重复概念的一些工具。在 Rust 中,一种这样的工具就是 *泛型,generics*:将一些具体类型或其他属性的替身抽象出来。对于在编译及运行代码时泛型处有着什么,咱们无需知悉就可以表达泛型的行为,或与其他泛型之间的关系,abstract stand-ins for concret types or other properties. We can express the bevavior of generics or how they relate to other generics without knowing what will be in their place when compiling and running the code。 4 | 5 | 与函数取一些未知值,以在多个具体值上运行函数体中同样代码的方式一样,其也可以取一些泛型的参数,而非像是 `i32` 或 `String` 这样的具体类型。事实上,前面在第 6 章的 `Option`,第 8 章的 `Vec` 和 `HashMap`,还有第 9 章的 `Result` 中,就已经用到了泛型特性。本章中,将探讨怎样定义咱们自己的、带有泛型特性的类型、函数及方法! 6 | 7 | 首先,这里会回顾怎样对函数进行凝练,从而减少代码重复。随后会使用同样技巧,来将两个只是参数类型不同的函数,构造为一个泛型函数。这里还会说明,怎样在结构体与枚举定义中使用泛型。 8 | 9 | 接着就会掌握怎样使用 *特质,traits*,来以泛型方式定义动作行为。可将特质与泛型结合,来将某个泛型约束为只接受有着特定行为的那些类型,而不再是任意类型。 10 | 11 | 最后,这里将讨论 *生命周期,lifetimes*:给到编译器有关引用之间关系信息的各种泛型。生命周期特性实现了给到编译器有关借用值的足够信息,从而在相比于没有咱们帮助而未给到这些信息时,编译器就能够于更多的不同情形下,确保这些引用的有效性。 12 | 13 | 14 | ## 通过提取出函数,而去除重复 15 | 16 | 泛型特性允许咱们以表示多种类型方式的占位符,替换掉特定类型,而消除代码重复。在进入到泛型语法之前,咱们先来看看,怎样以不涉及泛型的,而是用表示多个值的占位符替换特定值,提取出函数的方式消除重复。随后就会把这同样技巧,应用到提取泛型函数上!通过看到如何识别出可提取到函数中的重复代码,咱们就将开始识别出可使用泛型特性的重复代码。 17 | 18 | 这里会以下面清单 10-1 中,找出清单里极大数的简短程序开始。 19 | 20 | 文件名:`src/main.rs` 21 | 22 | ```rust 23 | fn main() { 24 | let number_list = vec! [34, 50, 25, 100, 65]; 25 | 26 | let mut largest = &number_list[0]; 27 | 28 | for number in &number_list { 29 | if number > largest { 30 | largest = number; 31 | } 32 | } 33 | 34 | println! ("极大数为 {}", largest); 35 | } 36 | ``` 37 | 38 | *清单 10-1:找出某个数字清单中的极大数* 39 | 40 | 这里将一个整数清单,存储在了变量 `number_list` 中,并将到该清单中第一个数字的引用,放在一个名为 `largest` 的变量里。这里随后对那个清单中的全部数字进行迭代,并在当前数字大于存储在 `largest` 中的数字时,替换掉那个变量中的引用。而在当前数小于或等于至今所见到的极大数时,那个变量则不会改变,而代码会继续到清单中的下一个数。在对清单中的全部数字进行审视后,`largest` 就应指向那个极大数,在此示例中即为 `100`。 41 | 42 | 现在咱们接受了找出两个不同数字清单中极大数的任务。为完成这个任务,咱们可以选择重复清单 10-1 中的代码,并在程序中两个不同位置,使用那相同逻辑,如下清单 10-2 中所示。 43 | 44 | 文件名:`src/main.rs` 45 | 46 | ```rust 47 | fn main() { 48 | let number_list = vec! [34, 50, 25, 100, 65]; 49 | 50 | let mut largest = &number_list[0]; 51 | 52 | for number in &number_list { 53 | if number > largest { 54 | largest = number; 55 | } 56 | } 57 | 58 | println! ("极大数为 {}", largest); 59 | 60 | let number_list = vec! [102, 34, 6000, 89, 54, 2, 43, 8]; 61 | 62 | let mut largest = &number_list[0]; 63 | 64 | for number in &number_list { 65 | if number > largest { 66 | largest = number; 67 | } 68 | } 69 | 70 | println! ("极大数为 {}", largest); 71 | } 72 | ``` 73 | 74 | *清单 10-2:找出 **两个** 数字清单中最大数的代码* 75 | 76 | 尽管此代码工作了,但那些重复代码则是乏味且容易出错的。在修改此代码时,还必须记住在多个地方更新代码。 77 | 78 | 为消除这种重复,咱们将通过定义一个运行在于参数中所传入的任意整数清单之上的函数,来消除这种重复。此方案会令到这里的代码更清楚,并实现了找出某个清单中极大数这一概念的抽象表达。 79 | 80 | 在下面的清单 10-3 中,咱们就把找出极大数的代码,提取到了一个名为 `largest` 的函数中。随后调用了该函数来找出了清单 10-2 中两个数字清单的极大数。将来咱们还可以在可能遇到的任何其他 `i32` 值清单上,使用这个函数。 81 | 82 | 文件名:`src/main.rs` 83 | 84 | ```rust 85 | fn largest(list: &[i32]) -> &i32 { 86 | let mut largest = &list[0]; 87 | 88 | for item in list { 89 | if item > largest { 90 | largest = item; 91 | } 92 | } 93 | 94 | largest 95 | } 96 | 97 | fn main() { 98 | let number_list = vec! [34, 50, 25, 100, 65]; 99 | 100 | let result = largest(&number_list); 101 | println! ("极大数为 {}", result); 102 | 103 | let number_list = vec! [102, 34, 6000, 89, 54, 2, 43, 8]; 104 | 105 | let result = largest(&number_list); 106 | println! ("极大数为 {}", result); 107 | } 108 | ``` 109 | 110 | *清单 10-3:抽象后的找出两个清单中极大数的代码* 111 | 112 | 这个 `largest` 函数有着一个名为 `list` 的参数,该参数表示了任意的、可能传入到该函数的一些 `i32` 值的切片。那么由此而来,在调用该函数时,该代码就会运行在所传入的那些特定值上。 113 | 114 | 总的来说,以下就是将代码从清单 10-2 修改为清单 10-3 所用的步骤: 115 | 116 | 1. 识别出重复代码; 117 | 2. 将重复代码提取到目标函数的函数体中,并在函数签名中指定重复代码的输入与输出值; 118 | 3. 将重复代码的两个实例,更新为调用这个提取出的函数。 119 | 120 | 接下来,就要在泛型下,使用这些同样步骤来降低代码重复了。与函数体可以在抽象的 `list`, 而非具体值上运作的方式一样,泛型实现了代码在抽象类型上的操作。 121 | 122 | 比如,假设说这里有两个函数:一个时在 `i32` 值的切片中,找出极大项,而另一个是在 `char` 值的切片中,找出极大项。那该怎样消除重复呢?下面就来解决这个问题! 123 | 124 | 125 | (End) 126 | 127 | 128 | -------------------------------------------------------------------------------- /src/images/15-04.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | l1 14 | 15 | 5 16 | 17 | 18 | 19 | 20 | 21 | l2 22 | 23 | 10 24 | 25 | 26 | 27 | 28 | 29 | l1:c->l2:data 30 | 31 | 32 | 33 | 34 | 35 | invisible_end 36 | 37 | 38 | 39 | 40 | l2:c->invisible_end:n 41 | 42 | 43 | 44 | 45 | invisible_start 46 | 47 | 48 | 49 | 50 | invisible_start:n->l1 51 | 52 | 53 | 54 | 55 | 56 | invisible_start:s->invisible_end:s 57 | 58 | 59 | 60 | 61 | a 62 | 63 | a 64 | 65 | 66 | 67 | a->l1:n 68 | 69 | 70 | 71 | 72 | 73 | b 74 | 75 | b 76 | 77 | 78 | 79 | b->l2:n 80 | 81 | 82 | 83 | 84 | 85 | --------------------------------------------------------------------------------