From 1d8363e408a975108aa284b1bba76fdb0c4d95c8 Mon Sep 17 00:00:00 2001 From: GaoJie Date: Wed, 6 Aug 2025 16:43:35 +0800 Subject: [PATCH 01/10] finish --- exercises/00_intro/intro1.rs | 1 + exercises/00_intro/intro2.rs | 2 +- exercises/01_variables/README.md | 2 +- exercises/01_variables/variables1.rs | 2 +- exercises/01_variables/variables2.rs | 4 +-- exercises/01_variables/variables3.rs | 2 +- exercises/01_variables/variables4.rs | 7 ++-- exercises/01_variables/variables5.rs | 6 ++-- exercises/01_variables/variables6.rs | 2 +- exercises/02_functions/functions1.rs | 3 ++ exercises/02_functions/functions2.rs | 2 +- exercises/02_functions/functions3.rs | 2 +- exercises/02_functions/functions4.rs | 2 +- exercises/02_functions/functions5.rs | 2 +- exercises/03_if/if1.rs | 5 +++ exercises/03_if/if2.rs | 8 +++-- exercises/03_if/if3.rs | 4 +-- .../04_primitive_types/primitive_types1.rs | 1 + .../04_primitive_types/primitive_types2.rs | 2 +- .../04_primitive_types/primitive_types3.rs | 3 +- .../04_primitive_types/primitive_types4.rs | 2 +- .../04_primitive_types/primitive_types5.rs | 1 + .../04_primitive_types/primitive_types6.rs | 2 +- exercises/05_vecs/vecs1.rs | 4 +-- exercises/05_vecs/vecs2.rs | 8 ++--- .../06_move_semantics/move_semantics1.rs | 4 +-- .../06_move_semantics/move_semantics2.rs | 2 +- .../06_move_semantics/move_semantics3.rs | 2 +- .../06_move_semantics/move_semantics4.rs | 2 +- .../06_move_semantics/move_semantics5.rs | 10 +++--- exercises/07_structs/structs1.rs | 8 ++++- exercises/07_structs/structs2.rs | 1 + exercises/07_structs/structs3.rs | 6 ++-- exercises/08_enums/README.md | 4 +-- exercises/08_enums/enums1.rs | 5 +++ exercises/08_enums/enums2.rs | 5 +++ exercises/08_enums/enums3.rs | 7 ++++ exercises/09_strings/strings1.rs | 2 +- exercises/09_strings/strings2.rs | 2 +- exercises/09_strings/strings3.rs | 4 ++- exercises/09_strings/strings4.rs | 23 ++++++------ exercises/10_modules/modules1.rs | 2 +- exercises/10_modules/modules2.rs | 2 ++ exercises/10_modules/modules3.rs | 1 + exercises/11_hashmaps/hashmaps1.rs | 6 +++- exercises/11_hashmaps/hashmaps2.rs | 3 ++ exercises/11_hashmaps/hashmaps3.rs | 14 ++++++++ exercises/12_options/options1.rs | 35 ++++++++++++------- exercises/12_options/options2.rs | 12 ++++--- exercises/12_options/options3.rs | 8 ++--- exercises/13_error_handling/README.md | 6 ++-- exercises/13_error_handling/errors1.rs | 6 ++-- exercises/13_error_handling/errors2.rs | 2 +- exercises/13_error_handling/errors3.rs | 5 ++- exercises/13_error_handling/errors4.rs | 8 ++++- exercises/13_error_handling/errors5.rs | 4 +-- exercises/13_error_handling/errors6.rs | 6 +++- exercises/14_generics/generics1.rs | 2 +- exercises/14_generics/generics2.rs | 14 +++++--- exercises/15_traits/traits1.rs | 4 +++ exercises/15_traits/traits2.rs | 7 ++++ exercises/15_traits/traits3.rs | 5 ++- exercises/15_traits/traits4.rs | 2 +- exercises/15_traits/traits5.rs | 2 +- exercises/16_lifetimes/lifetimes1.rs | 2 +- exercises/16_lifetimes/lifetimes2.rs | 8 ++--- exercises/16_lifetimes/lifetimes3.rs | 6 ++-- exercises/17_tests/tests1.rs | 6 ++-- exercises/17_tests/tests2.rs | 8 ++--- exercises/17_tests/tests3.rs | 10 +++--- exercises/18_iterators/iterators1.rs | 10 +++--- exercises/18_iterators/iterators2.rs | 10 ++++-- exercises/18_iterators/iterators3.rs | 27 +++++++++----- exercises/18_iterators/iterators4.rs | 1 + exercises/18_iterators/iterators5.rs | 7 ++++ exercises/19_smart_pointers/arc1.rs | 2 ++ exercises/19_smart_pointers/box1.rs | 10 ++++-- exercises/19_smart_pointers/cow1.rs | 8 +++-- exercises/19_smart_pointers/rc1.rs | 9 +++-- exercises/20_threads/threads1.rs | 2 ++ exercises/20_threads/threads2.rs | 8 +++-- exercises/20_threads/threads3.rs | 7 ++-- exercises/21_macros/README.md | 3 +- exercises/21_macros/macros1.rs | 2 +- exercises/21_macros/macros2.rs | 7 ++-- exercises/21_macros/macros3.rs | 1 + exercises/21_macros/macros4.rs | 2 +- exercises/22_clippy/clippy1.rs | 2 +- exercises/22_clippy/clippy2.rs | 2 +- exercises/22_clippy/clippy3.rs | 23 ++++++------ exercises/23_conversions/as_ref_mut.rs | 12 ++++--- exercises/23_conversions/from_into.rs | 29 ++++++++++++++- exercises/23_conversions/from_str.rs | 26 +++++++++++++- exercises/23_conversions/try_from_into.rs | 28 +++++++++++++-- exercises/23_conversions/using_as.rs | 2 +- exercises/quizzes/quiz1.rs | 10 +++++- exercises/quizzes/quiz2.rs | 15 ++++++++ exercises/quizzes/quiz3.rs | 22 +++++++++--- 98 files changed, 456 insertions(+), 193 deletions(-) diff --git a/exercises/00_intro/intro1.rs b/exercises/00_intro/intro1.rs index 172a6ab1f2..7870c32ecf 100644 --- a/exercises/00_intro/intro1.rs +++ b/exercises/00_intro/intro1.rs @@ -21,4 +21,5 @@ fn main() { println!("The file of this exercise is `exercises/00_intro/intro1.rs`. Have a look!"); println!("The current exercise path will be always shown under the progress bar."); println!("You can click on the path to open the exercise file in your editor."); + println!("finish"); } diff --git a/exercises/00_intro/intro2.rs b/exercises/00_intro/intro2.rs index c6cb6451ae..03e376ed35 100644 --- a/exercises/00_intro/intro2.rs +++ b/exercises/00_intro/intro2.rs @@ -1,4 +1,4 @@ fn main() { // TODO: Fix the code to print "Hello world!". - printline!("Hello world!"); + println!("Hello world!"); } diff --git a/exercises/01_variables/README.md b/exercises/01_variables/README.md index 5ba2efcaa2..7964ff29f4 100644 --- a/exercises/01_variables/README.md +++ b/exercises/01_variables/README.md @@ -1,7 +1,7 @@ # Variables In Rust, variables are immutable by default. -When a variable is immutable, once a value is bound to a name, you can't change that value. +When a variable is immutable, once a value is bound to a name, you can’t change that value. You can make them mutable by adding `mut` in front of the variable name. ## Further information diff --git a/exercises/01_variables/variables1.rs b/exercises/01_variables/variables1.rs index f83b44d415..ec1bcacb53 100644 --- a/exercises/01_variables/variables1.rs +++ b/exercises/01_variables/variables1.rs @@ -1,6 +1,6 @@ fn main() { // TODO: Add the missing keyword. - x = 5; + let x = 5; println!("x has the value {x}"); } diff --git a/exercises/01_variables/variables2.rs b/exercises/01_variables/variables2.rs index e2a360351a..585beccd7d 100644 --- a/exercises/01_variables/variables2.rs +++ b/exercises/01_variables/variables2.rs @@ -1,8 +1,8 @@ fn main() { // TODO: Change the line below to fix the compiler error. - let x; + let x = 10; - if x == 10 { + if 10 == x { println!("x is ten!"); } else { println!("x is not ten!"); diff --git a/exercises/01_variables/variables3.rs b/exercises/01_variables/variables3.rs index 06f35bb1e2..2bd4e62baf 100644 --- a/exercises/01_variables/variables3.rs +++ b/exercises/01_variables/variables3.rs @@ -1,6 +1,6 @@ fn main() { // TODO: Change the line below to fix the compiler error. - let x: i32; + let x: i32 = 40; println!("Number {x}"); } diff --git a/exercises/01_variables/variables4.rs b/exercises/01_variables/variables4.rs index 6c138b18b9..a41c360ac4 100644 --- a/exercises/01_variables/variables4.rs +++ b/exercises/01_variables/variables4.rs @@ -1,8 +1,7 @@ -// TODO: Fix the compiler error. fn main() { - let x = 3; + let mut x = 3; // 加上 mut 表示 x 是可变的 println!("Number {x}"); - x = 5; // Don't change this line + x = 5; // 现在可以修改了 println!("Number {x}"); -} +} \ No newline at end of file diff --git a/exercises/01_variables/variables5.rs b/exercises/01_variables/variables5.rs index cf5620da5f..261dabfed4 100644 --- a/exercises/01_variables/variables5.rs +++ b/exercises/01_variables/variables5.rs @@ -1,8 +1,8 @@ fn main() { let number = "T-H-R-E-E"; // Don't change this line - println!("Spell a number: {number}"); + println!("Spell a number: {}", number); // TODO: Fix the compiler error by changing the line below without renaming the variable. - number = 3; + let number = 3; // 使用变量遮蔽,重新绑定为整数 println!("Number plus two is: {}", number + 2); -} +} \ No newline at end of file diff --git a/exercises/01_variables/variables6.rs b/exercises/01_variables/variables6.rs index 4a040fddac..deb33ed9dd 100644 --- a/exercises/01_variables/variables6.rs +++ b/exercises/01_variables/variables6.rs @@ -1,5 +1,5 @@ // TODO: Change the line below to fix the compiler error. -const NUMBER = 3; +const NUMBER: i32 = 3; fn main() { println!("Number: {NUMBER}"); diff --git a/exercises/02_functions/functions1.rs b/exercises/02_functions/functions1.rs index a812c21bf2..ecf6f76a37 100644 --- a/exercises/02_functions/functions1.rs +++ b/exercises/02_functions/functions1.rs @@ -1,5 +1,8 @@ // TODO: Add some function with the name `call_me` without arguments or a return value. +fn call_me() { + // 函数体可以为空 +} fn main() { call_me(); // Don't change this line } diff --git a/exercises/02_functions/functions2.rs b/exercises/02_functions/functions2.rs index 2c773c6b7f..a446c0fb2b 100644 --- a/exercises/02_functions/functions2.rs +++ b/exercises/02_functions/functions2.rs @@ -1,5 +1,5 @@ // TODO: Add the missing type of the argument `num` after the colon `:`. -fn call_me(num:) { +fn call_me(num:usize) { for i in 0..num { println!("Ring! Call number {}", i + 1); } diff --git a/exercises/02_functions/functions3.rs b/exercises/02_functions/functions3.rs index 8d65477219..48854fbc70 100644 --- a/exercises/02_functions/functions3.rs +++ b/exercises/02_functions/functions3.rs @@ -6,5 +6,5 @@ fn call_me(num: u8) { fn main() { // TODO: Fix the function call. - call_me(); + call_me(2); } diff --git a/exercises/02_functions/functions4.rs b/exercises/02_functions/functions4.rs index b22bffdaf2..60ab17d4f8 100644 --- a/exercises/02_functions/functions4.rs +++ b/exercises/02_functions/functions4.rs @@ -8,7 +8,7 @@ fn is_even(num: i64) -> bool { } // TODO: Fix the function signature. -fn sale_price(price: i64) -> { +fn sale_price(price: i64) -> i64{ if is_even(price) { price - 10 } else { diff --git a/exercises/02_functions/functions5.rs b/exercises/02_functions/functions5.rs index 34a2ac7dce..a063100408 100644 --- a/exercises/02_functions/functions5.rs +++ b/exercises/02_functions/functions5.rs @@ -1,6 +1,6 @@ // TODO: Fix the function body without changing the signature. fn square(num: i32) -> i32 { - num * num; + num * num } fn main() { diff --git a/exercises/03_if/if1.rs b/exercises/03_if/if1.rs index e5a3c5a5b2..b1a304d4ee 100644 --- a/exercises/03_if/if1.rs +++ b/exercises/03_if/if1.rs @@ -4,6 +4,11 @@ fn bigger(a: i32, b: i32) -> i32 { // Do not use: // - another function call // - additional variables + if a > b { + a + } else { + b + } } fn main() { diff --git a/exercises/03_if/if2.rs b/exercises/03_if/if2.rs index ca8493cc81..664769f702 100644 --- a/exercises/03_if/if2.rs +++ b/exercises/03_if/if2.rs @@ -2,8 +2,10 @@ fn picky_eater(food: &str) -> &str { if food == "strawberry" { "Yummy!" - } else { - 1 + }else if food == "potato" { + "I guess I can eat that." + }else { + "No thanks!" } } @@ -19,7 +21,7 @@ mod tests { #[test] fn yummy_food() { - // This means that calling `picky_eater` with the argument "strawberry" should return "Yummy!". + // This means that calling `picky_eater` with the argument "food" should return "Yummy!". assert_eq!(picky_eater("strawberry"), "Yummy!"); } diff --git a/exercises/03_if/if3.rs b/exercises/03_if/if3.rs index 89164eb218..96f81f9fad 100644 --- a/exercises/03_if/if3.rs +++ b/exercises/03_if/if3.rs @@ -3,11 +3,11 @@ fn animal_habitat(animal: &str) -> &str { let identifier = if animal == "crab" { 1 } else if animal == "gopher" { - 2.0 + 2 } else if animal == "snake" { 3 } else { - "Unknown" + 0 }; // Don't change the expression below! diff --git a/exercises/04_primitive_types/primitive_types1.rs b/exercises/04_primitive_types/primitive_types1.rs index 84923c7500..c464bd9f10 100644 --- a/exercises/04_primitive_types/primitive_types1.rs +++ b/exercises/04_primitive_types/primitive_types1.rs @@ -9,6 +9,7 @@ fn main() { // TODO: Define a boolean variable with the name `is_evening` before the `if` statement below. // The value of the variable should be the negation (opposite) of `is_morning`. // let … + let is_evening = !is_morning; if is_evening { println!("Good evening!"); } diff --git a/exercises/04_primitive_types/primitive_types2.rs b/exercises/04_primitive_types/primitive_types2.rs index 14018475dd..035f8bb8c0 100644 --- a/exercises/04_primitive_types/primitive_types2.rs +++ b/exercises/04_primitive_types/primitive_types2.rs @@ -17,7 +17,7 @@ fn main() { // Try a letter, try a digit (in single quotes), try a special character, try a character // from a different language than your own, try an emoji 😉 // let your_character = ''; - + let your_character = '😉'; // 这里可以替换成你喜欢的任意字符 if your_character.is_alphabetic() { println!("Alphabetical!"); } else if your_character.is_numeric() { diff --git a/exercises/04_primitive_types/primitive_types3.rs b/exercises/04_primitive_types/primitive_types3.rs index 9b79c0cf2a..60533934d6 100644 --- a/exercises/04_primitive_types/primitive_types3.rs +++ b/exercises/04_primitive_types/primitive_types3.rs @@ -1,7 +1,8 @@ fn main() { // TODO: Create an array called `a` with at least 100 elements in it. // let a = ??? - + let a = [0; 100]; // 100个元素,每个元素都是0 + if a.len() >= 100 { println!("Wow, that's a big array!"); } else { diff --git a/exercises/04_primitive_types/primitive_types4.rs b/exercises/04_primitive_types/primitive_types4.rs index 16e4fd9321..9fbccfd182 100644 --- a/exercises/04_primitive_types/primitive_types4.rs +++ b/exercises/04_primitive_types/primitive_types4.rs @@ -7,7 +7,7 @@ mod tests { #[test] fn slice_out_of_array() { let a = [1, 2, 3, 4, 5]; - + let nice_slice = &a[1..4]; // TODO: Get a slice called `nice_slice` out of the array `a` so that the test passes. // let nice_slice = ??? diff --git a/exercises/04_primitive_types/primitive_types5.rs b/exercises/04_primitive_types/primitive_types5.rs index 6e00ef51f8..3dce8638d2 100644 --- a/exercises/04_primitive_types/primitive_types5.rs +++ b/exercises/04_primitive_types/primitive_types5.rs @@ -3,6 +3,7 @@ fn main() { // TODO: Destructure the `cat` tuple in one statement so that the println works. // let /* your pattern here */ = cat; + let (name, age) = cat; println!("{name} is {age} years old"); } diff --git a/exercises/04_primitive_types/primitive_types6.rs b/exercises/04_primitive_types/primitive_types6.rs index a97e53110e..f8763a0f5a 100644 --- a/exercises/04_primitive_types/primitive_types6.rs +++ b/exercises/04_primitive_types/primitive_types6.rs @@ -7,7 +7,7 @@ mod tests { #[test] fn indexing_tuple() { let numbers = (1, 2, 3); - + let second = numbers.1; // TODO: Use a tuple index to access the second element of `numbers` // and assign it to a variable called `second`. // let second = ???; diff --git a/exercises/05_vecs/vecs1.rs b/exercises/05_vecs/vecs1.rs index 68e1affaa7..46442b21d0 100644 --- a/exercises/05_vecs/vecs1.rs +++ b/exercises/05_vecs/vecs1.rs @@ -1,10 +1,10 @@ fn array_and_vec() -> ([i32; 4], Vec) { let a = [10, 20, 30, 40]; // Array - + // TODO: Create a vector called `v` which contains the exact same elements as in the array `a`. // Use the vector macro. // let v = ???; - + let v = vec![10, 20, 30, 40]; (a, v) } diff --git a/exercises/05_vecs/vecs2.rs b/exercises/05_vecs/vecs2.rs index a9be2580f2..a4afd99283 100644 --- a/exercises/05_vecs/vecs2.rs +++ b/exercises/05_vecs/vecs2.rs @@ -4,6 +4,7 @@ fn vec_loop(input: &[i32]) -> Vec { for element in input { // TODO: Multiply each element in the `input` slice by 2 and push it to // the `output` vector. + output.push(element * 2); } output @@ -21,12 +22,7 @@ fn vec_map(input: &[i32]) -> Vec { // by 2, but with iterator mapping instead of manually pushing into an empty // vector. // See the example in the function `vec_map_example` above. - input - .iter() - .map(|element| { - // ??? - }) - .collect() + input.iter().map(|element| element * 2).collect() } fn main() { diff --git a/exercises/06_move_semantics/move_semantics1.rs b/exercises/06_move_semantics/move_semantics1.rs index 4eb3d618ef..c3fe8a7652 100644 --- a/exercises/06_move_semantics/move_semantics1.rs +++ b/exercises/06_move_semantics/move_semantics1.rs @@ -1,6 +1,6 @@ // TODO: Fix the compiler error in this function. -fn fill_vec(vec: Vec) -> Vec { - let vec = vec; +fn fill_vec(mut vec: Vec) -> Vec { + let mut vec = vec; vec.push(88); diff --git a/exercises/06_move_semantics/move_semantics2.rs b/exercises/06_move_semantics/move_semantics2.rs index a3ab7a0f18..e205b81357 100644 --- a/exercises/06_move_semantics/move_semantics2.rs +++ b/exercises/06_move_semantics/move_semantics2.rs @@ -20,7 +20,7 @@ mod tests { fn move_semantics2() { let vec0 = vec![22, 44, 66]; - let vec1 = fill_vec(vec0); + let vec1 = fill_vec(vec0.clone()); assert_eq!(vec0, [22, 44, 66]); assert_eq!(vec1, [22, 44, 66, 88]); diff --git a/exercises/06_move_semantics/move_semantics3.rs b/exercises/06_move_semantics/move_semantics3.rs index 11dbbbebff..4a90c2117c 100644 --- a/exercises/06_move_semantics/move_semantics3.rs +++ b/exercises/06_move_semantics/move_semantics3.rs @@ -1,5 +1,5 @@ // TODO: Fix the compiler error in the function without adding any new line. -fn fill_vec(vec: Vec) -> Vec { +fn fill_vec(mut vec: Vec) -> Vec { vec.push(88); vec diff --git a/exercises/06_move_semantics/move_semantics4.rs b/exercises/06_move_semantics/move_semantics4.rs index 56da988cd4..89b412f093 100644 --- a/exercises/06_move_semantics/move_semantics4.rs +++ b/exercises/06_move_semantics/move_semantics4.rs @@ -10,8 +10,8 @@ mod tests { fn move_semantics4() { let mut x = Vec::new(); let y = &mut x; - let z = &mut x; y.push(42); + let z = &mut x; z.push(13); assert_eq!(x, [42, 13]); } diff --git a/exercises/06_move_semantics/move_semantics5.rs b/exercises/06_move_semantics/move_semantics5.rs index cd0dafd08d..a719da3c6b 100644 --- a/exercises/06_move_semantics/move_semantics5.rs +++ b/exercises/06_move_semantics/move_semantics5.rs @@ -4,13 +4,13 @@ // removing references (the character `&`). // Shouldn't take ownership -fn get_char(data: String) -> char { +fn get_char(data: &String) -> char { data.chars().last().unwrap() } // Should take ownership -fn string_uppercase(mut data: &String) { - data = data.to_uppercase(); +fn string_uppercase(data: String) { + let data = data.to_uppercase(); println!("{data}"); } @@ -18,7 +18,7 @@ fn string_uppercase(mut data: &String) { fn main() { let data = "Rust is great!".to_string(); - get_char(data); + get_char(&data); - string_uppercase(&data); + string_uppercase(data.clone()); } diff --git a/exercises/07_structs/structs1.rs b/exercises/07_structs/structs1.rs index 959c4c6a68..62eaade56f 100644 --- a/exercises/07_structs/structs1.rs +++ b/exercises/07_structs/structs1.rs @@ -1,9 +1,12 @@ struct ColorRegularStruct { // TODO: Add the fields that the test `regular_structs` expects. // What types should the fields have? What are the minimum and maximum values for RGB colors? + red: u8, + green: u8, + blue: u8, } -struct ColorTupleStruct(/* TODO: Add the fields that the test `tuple_structs` expects */); +struct ColorTupleStruct(u8, u8, u8); #[derive(Debug)] struct UnitStruct; @@ -20,6 +23,7 @@ mod tests { fn regular_structs() { // TODO: Instantiate a regular struct. // let green = + let green = ColorRegularStruct { red: 0, green: 255, blue: 0 }; assert_eq!(green.red, 0); assert_eq!(green.green, 255); @@ -30,6 +34,7 @@ mod tests { fn tuple_structs() { // TODO: Instantiate a tuple struct. // let green = + let green = ColorTupleStruct(0, 255, 0); assert_eq!(green.0, 0); assert_eq!(green.1, 255); @@ -40,6 +45,7 @@ mod tests { fn unit_structs() { // TODO: Instantiate a unit struct. // let unit_struct = + let unit_struct = UnitStruct; let message = format!("{unit_struct:?}s are fun!"); assert_eq!(message, "UnitStructs are fun!"); diff --git a/exercises/07_structs/structs2.rs b/exercises/07_structs/structs2.rs index 79141af95d..edd5d2ad09 100644 --- a/exercises/07_structs/structs2.rs +++ b/exercises/07_structs/structs2.rs @@ -35,6 +35,7 @@ mod tests { // TODO: Create your own order using the update syntax and template above! // let your_order = + let your_order = Order {name: String::from("Hacker in Rust"), count: 1, ..order_template}; assert_eq!(your_order.name, "Hacker in Rust"); assert_eq!(your_order.year, order_template.year); diff --git a/exercises/07_structs/structs3.rs b/exercises/07_structs/structs3.rs index 69e5ced7f8..9e9f05b53e 100644 --- a/exercises/07_structs/structs3.rs +++ b/exercises/07_structs/structs3.rs @@ -24,14 +24,16 @@ impl Package { } // TODO: Add the correct return type to the function signature. - fn is_international(&self) { + fn is_international(&self) -> bool { // TODO: Read the tests that use this method to find out when a package // is considered international. + self.sender_country != self.recipient_country } // TODO: Add the correct return type to the function signature. - fn get_fees(&self, cents_per_gram: u32) { + fn get_fees(&self, cents_per_gram: u32) -> u32{ // TODO: Calculate the package's fees. + self.weight_in_grams * cents_per_gram } } diff --git a/exercises/08_enums/README.md b/exercises/08_enums/README.md index b05cb42260..30d4d91db2 100644 --- a/exercises/08_enums/README.md +++ b/exercises/08_enums/README.md @@ -1,10 +1,10 @@ # Enums Rust allows you to define types called "enums" which enumerate possible values. -Enums are a feature in many languages, but their capabilities differ in each language. Rust's enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell. +Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell. Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration. ## Further information - [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html) -- [Pattern syntax](https://doc.rust-lang.org/book/ch19-03-pattern-syntax.html) +- [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html) diff --git a/exercises/08_enums/enums1.rs b/exercises/08_enums/enums1.rs index c0d0c308d2..c45ac7aa22 100644 --- a/exercises/08_enums/enums1.rs +++ b/exercises/08_enums/enums1.rs @@ -1,6 +1,11 @@ #[derive(Debug)] enum Message { // TODO: Define a few types of messages as used below. + Resize, + Move, + Echo, + ChangeColor, + Quit, } fn main() { diff --git a/exercises/08_enums/enums2.rs b/exercises/08_enums/enums2.rs index d70f6398d1..cf862c2757 100644 --- a/exercises/08_enums/enums2.rs +++ b/exercises/08_enums/enums2.rs @@ -7,6 +7,11 @@ struct Point { #[derive(Debug)] enum Message { // TODO: Define the different variants used below. + Resize { width: u64, height: u64 }, + Move(Point), + Echo(String), + ChangeColor(u8, u8, u8), + Quit, } impl Message { diff --git a/exercises/08_enums/enums3.rs b/exercises/08_enums/enums3.rs index cb05f657c2..9fa1e6a976 100644 --- a/exercises/08_enums/enums3.rs +++ b/exercises/08_enums/enums3.rs @@ -46,6 +46,13 @@ impl State { fn process(&mut self, message: Message) { // TODO: Create a match expression to process the different message // variants using the methods defined above. + match message { + Message::Resize { width, height } => self.resize(width, height), + Message::Move(point) => self.move_position(point), + Message::Echo(s) => self.echo(s), + Message::ChangeColor(r, g, b) => self.change_color(r, g, b), + Message::Quit => self.quit(), + } } } diff --git a/exercises/09_strings/strings1.rs b/exercises/09_strings/strings1.rs index 6abdbb48f0..06755aae40 100644 --- a/exercises/09_strings/strings1.rs +++ b/exercises/09_strings/strings1.rs @@ -1,6 +1,6 @@ // TODO: Fix the compiler error without changing the function signature. fn current_favorite_color() -> String { - "blue" + "blue".to_string() } fn main() { diff --git a/exercises/09_strings/strings2.rs b/exercises/09_strings/strings2.rs index 93d9cb6b7f..2ed89c5666 100644 --- a/exercises/09_strings/strings2.rs +++ b/exercises/09_strings/strings2.rs @@ -6,7 +6,7 @@ fn is_a_color_word(attempt: &str) -> bool { fn main() { let word = String::from("green"); // Don't change this line. - if is_a_color_word(word) { + if is_a_color_word(&word) { println!("That is a color word I know!"); } else { println!("That is not a color word I know."); diff --git a/exercises/09_strings/strings3.rs b/exercises/09_strings/strings3.rs index f5e45b0ffc..6b97e4adcb 100644 --- a/exercises/09_strings/strings3.rs +++ b/exercises/09_strings/strings3.rs @@ -1,13 +1,16 @@ fn trim_me(input: &str) -> &str { // TODO: Remove whitespace from both ends of a string. + input.trim() } fn compose_me(input: &str) -> String { // TODO: Add " world!" to the string! There are multiple ways to do this. + format!("{input} world!") } fn replace_me(input: &str) -> String { // TODO: Replace "cars" in the string with "balloons". + input.replace("cars", "balloons") } fn main() { @@ -23,7 +26,6 @@ mod tests { assert_eq!(trim_me("Hello! "), "Hello!"); assert_eq!(trim_me(" What's up!"), "What's up!"); assert_eq!(trim_me(" Hola! "), "Hola!"); - assert_eq!(trim_me("Hi!"), "Hi!"); } #[test] diff --git a/exercises/09_strings/strings4.rs b/exercises/09_strings/strings4.rs index 473072636d..dd7bd083f1 100644 --- a/exercises/09_strings/strings4.rs +++ b/exercises/09_strings/strings4.rs @@ -13,25 +13,24 @@ fn string(arg: String) { // Your task is to replace `placeholder(…)` with either `string_slice(…)` // or `string(…)` depending on what you think each value is. fn main() { - placeholder("blue"); + string_slice("blue"); - placeholder("red".to_string()); + string("red".to_string()); - placeholder(String::from("hi")); + string(String::from("hi")); - placeholder("rust is fun!".to_owned()); + string("rust is fun!".to_owned()); - placeholder("nice weather".into()); + string("nice weather".into()); - placeholder(format!("Interpolation {}", "Station")); + string(format!("Interpolation {}", "Station")); - // WARNING: This is byte indexing, not character indexing. - // Character indexing can be done using `s.chars().nth(INDEX)`. - placeholder(&String::from("abc")[0..1]); + // Byte slice -> &str + string_slice(&String::from("abc")[0..1]); - placeholder(" hello there ".trim()); + string_slice(" hello there ".trim()); - placeholder("Happy Monday!".replace("Mon", "Tues")); + string("Happy Monday!".replace("Mon", "Tues")); - placeholder("mY sHiFt KeY iS sTiCkY".to_lowercase()); + string("mY sHiFt KeY iS sTiCkY".to_lowercase()); } diff --git a/exercises/10_modules/modules1.rs b/exercises/10_modules/modules1.rs index d97ab23a53..81981dfca5 100644 --- a/exercises/10_modules/modules1.rs +++ b/exercises/10_modules/modules1.rs @@ -5,7 +5,7 @@ mod sausage_factory { String::from("Ginger") } - fn make_sausage() { + pub fn make_sausage() { get_secret_recipe(); println!("sausage!"); } diff --git a/exercises/10_modules/modules2.rs b/exercises/10_modules/modules2.rs index 782a70eace..0d2b298801 100644 --- a/exercises/10_modules/modules2.rs +++ b/exercises/10_modules/modules2.rs @@ -5,6 +5,8 @@ mod delicious_snacks { // TODO: Add the following two `use` statements after fixing them. // use self::fruits::PEAR as ???; // use self::veggies::CUCUMBER as ???; + pub use self::fruits::PEAR as fruit; + pub use self::veggies::CUCUMBER as veggie; mod fruits { pub const PEAR: &str = "Pear"; diff --git a/exercises/10_modules/modules3.rs b/exercises/10_modules/modules3.rs index 691608d275..21f4c10bc3 100644 --- a/exercises/10_modules/modules3.rs +++ b/exercises/10_modules/modules3.rs @@ -4,6 +4,7 @@ // TODO: Bring `SystemTime` and `UNIX_EPOCH` from the `std::time` module into // your scope. Bonus style points if you can do it with one line! // use ???; +use std::time::{SystemTime, UNIX_EPOCH}; fn main() { match SystemTime::now().duration_since(UNIX_EPOCH) { diff --git a/exercises/11_hashmaps/hashmaps1.rs b/exercises/11_hashmaps/hashmaps1.rs index 74001d0432..1d3a48f220 100644 --- a/exercises/11_hashmaps/hashmaps1.rs +++ b/exercises/11_hashmaps/hashmaps1.rs @@ -9,12 +9,16 @@ use std::collections::HashMap; fn fruit_basket() -> HashMap { // TODO: Declare the hash map. // let mut basket = + let mut basket = HashMap::new(); // Two bananas are already given for you :) basket.insert(String::from("banana"), 2); + // TODO: Put more fruits in your basket. - + basket.insert(String::from("apple"), 2); + basket.insert(String::from("mango"), 2); + basket } diff --git a/exercises/11_hashmaps/hashmaps2.rs b/exercises/11_hashmaps/hashmaps2.rs index e9f53fea3c..cc136306d5 100644 --- a/exercises/11_hashmaps/hashmaps2.rs +++ b/exercises/11_hashmaps/hashmaps2.rs @@ -32,6 +32,9 @@ fn fruit_basket(basket: &mut HashMap) { // TODO: Insert new fruits if they are not already present in the // basket. Note that you are not allowed to put any type of fruit that's // already present! + if !basket.contains_key(&fruit) { + basket.insert(fruit, 1); + } } } diff --git a/exercises/11_hashmaps/hashmaps3.rs b/exercises/11_hashmaps/hashmaps3.rs index 5b390ab9b8..5882cfb5c0 100644 --- a/exercises/11_hashmaps/hashmaps3.rs +++ b/exercises/11_hashmaps/hashmaps3.rs @@ -31,6 +31,20 @@ fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> { // Keep in mind that goals scored by team 1 will be the number of goals // conceded by team 2. Similarly, goals scored by team 2 will be the // number of goals conceded by team 1. + // 获取或插入默认记录 + // 先获取并更新 team 1 + { + let team_1_entry = scores.entry(team_1_name).or_default(); + team_1_entry.goals_scored += team_1_score; + team_1_entry.goals_conceded += team_2_score; + } + + // 再获取并更新 team 2 + { + let team_2_entry = scores.entry(team_2_name).or_default(); + team_2_entry.goals_scored += team_2_score; + team_2_entry.goals_conceded += team_1_score; + } } scores diff --git a/exercises/12_options/options1.rs b/exercises/12_options/options1.rs index d0c412a8d4..b3fbab3bca 100644 --- a/exercises/12_options/options1.rs +++ b/exercises/12_options/options1.rs @@ -1,9 +1,17 @@ -// This function returns how much ice cream there is left in the fridge. +// This function returns how much icecream there is left in the fridge. // If it's before 22:00 (24-hour system), then 5 scoops are left. At 22:00, -// someone eats it all, so no ice cream is left (value 0). Return `None` if +// someone eats it all, so no icecream is left (value 0). Return `None` if // `hour_of_day` is higher than 23. -fn maybe_ice_cream(hour_of_day: u16) -> Option { +fn maybe_icecream(hour_of_day: u16) -> Option { // TODO: Complete the function body. + if hour_of_day > 23 { + None + } else if hour_of_day < 22 { + Some(5) + } else { + // hour_of_day == 22 or 23 + Some(0) + } } fn main() { @@ -18,19 +26,20 @@ mod tests { fn raw_value() { // TODO: Fix this test. How do you get the value contained in the // Option? - let ice_creams = maybe_ice_cream(12); + let icecreams = maybe_icecream(12); - assert_eq!(ice_creams, 5); // Don't change this line. + // assert_eq!(icecreams, 5); // Don't change this line. + assert_eq!(icecreams.unwrap(), 5); } #[test] - fn check_ice_cream() { - assert_eq!(maybe_ice_cream(0), Some(5)); - assert_eq!(maybe_ice_cream(9), Some(5)); - assert_eq!(maybe_ice_cream(18), Some(5)); - assert_eq!(maybe_ice_cream(22), Some(0)); - assert_eq!(maybe_ice_cream(23), Some(0)); - assert_eq!(maybe_ice_cream(24), None); - assert_eq!(maybe_ice_cream(25), None); + fn check_icecream() { + assert_eq!(maybe_icecream(0), Some(5)); + assert_eq!(maybe_icecream(9), Some(5)); + assert_eq!(maybe_icecream(18), Some(5)); + assert_eq!(maybe_icecream(22), Some(0)); + assert_eq!(maybe_icecream(23), Some(0)); + assert_eq!(maybe_icecream(24), None); + assert_eq!(maybe_icecream(25), None); } } diff --git a/exercises/12_options/options2.rs b/exercises/12_options/options2.rs index 07c27c6ec2..227e2b8a4d 100644 --- a/exercises/12_options/options2.rs +++ b/exercises/12_options/options2.rs @@ -10,8 +10,10 @@ mod tests { let optional_target = Some(target); // TODO: Make this an if-let statement whose value is `Some`. - word = optional_target { + if let Some(word) = optional_target { assert_eq!(word, target); + } else { + panic!("Expected Some but found None"); } } @@ -29,10 +31,10 @@ mod tests { // TODO: Make this a while-let statement. Remember that `Vec::pop()` // adds another layer of `Option`. You can do nested pattern matching // in if-let and while-let statements. - integer = optional_integers.pop() { - assert_eq!(integer, cursor); - cursor -= 1; - } + while let Some(Some(integer)) = optional_integers.pop() { + assert_eq!(integer, cursor); + cursor -= 1; + } assert_eq!(cursor, 0); } diff --git a/exercises/12_options/options3.rs b/exercises/12_options/options3.rs index c97b1d3cf4..41b552d06e 100644 --- a/exercises/12_options/options3.rs +++ b/exercises/12_options/options3.rs @@ -8,10 +8,10 @@ fn main() { let optional_point = Some(Point { x: 100, y: 200 }); // TODO: Fix the compiler error by adding something to this match statement. - match optional_point { - Some(p) => println!("Coordinates are {},{}", p.x, p.y), - _ => panic!("No match!"), - } + match &optional_point { + Some(p) => println!("Co-ordinates are {},{}", p.x, p.y), + _ => panic!("No match!"), +} println!("{optional_point:?}"); // Don't change this line. } diff --git a/exercises/13_error_handling/README.md b/exercises/13_error_handling/README.md index 9b6674bc7a..3b21f2b782 100644 --- a/exercises/13_error_handling/README.md +++ b/exercises/13_error_handling/README.md @@ -1,8 +1,8 @@ # Error handling -Most errors aren't serious enough to require the program to stop entirely. -Sometimes, when a function fails, it's for a reason that you can easily interpret and respond to. -For example, if you try to open a file and that operation fails because the file doesn't exist, you might want to create the file instead of terminating the process. +Most errors aren’t serious enough to require the program to stop entirely. +Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to. +For example, if you try to open a file and that operation fails because the file doesn’t exist, you might want to create the file instead of terminating the process. ## Further information diff --git a/exercises/13_error_handling/errors1.rs b/exercises/13_error_handling/errors1.rs index e07fddc3cd..0cced95850 100644 --- a/exercises/13_error_handling/errors1.rs +++ b/exercises/13_error_handling/errors1.rs @@ -4,12 +4,12 @@ // construct to `Option` that can be used to express error conditions. Change // the function signature and body to return `Result` instead // of `Option`. -fn generate_nametag_text(name: String) -> Option { +fn generate_nametag_text(name: String) -> Result { if name.is_empty() { // Empty names aren't allowed - None + Err("Empty names aren't allowed".to_string()) } else { - Some(format!("Hi! My name is {name}")) + Ok(format!("Hi! My name is {name}")) } } diff --git a/exercises/13_error_handling/errors2.rs b/exercises/13_error_handling/errors2.rs index defe359b48..0678205ee4 100644 --- a/exercises/13_error_handling/errors2.rs +++ b/exercises/13_error_handling/errors2.rs @@ -21,7 +21,7 @@ fn total_cost(item_quantity: &str) -> Result { let cost_per_item = 5; // TODO: Handle the error case as described above. - let qty = item_quantity.parse::(); + let qty = item_quantity.parse::()?; // 这里用 ? 解包,如果失败会返回错误 Ok(qty * cost_per_item + processing_fee) } diff --git a/exercises/13_error_handling/errors3.rs b/exercises/13_error_handling/errors3.rs index 8e8c38a2a1..ddca969269 100644 --- a/exercises/13_error_handling/errors3.rs +++ b/exercises/13_error_handling/errors3.rs @@ -15,7 +15,8 @@ fn total_cost(item_quantity: &str) -> Result { // TODO: Fix the compiler error by changing the signature and body of the // `main` function. -fn main() { +// 修改main函数签名,支持?操作符 +fn main() -> Result<(), ParseIntError> { let mut tokens = 100; let pretend_user_input = "8"; @@ -24,8 +25,10 @@ fn main() { if cost > tokens { println!("You can't afford that many!"); + Ok(()) } else { tokens -= cost; println!("You now have {tokens} tokens."); + Ok(()) } } diff --git a/exercises/13_error_handling/errors4.rs b/exercises/13_error_handling/errors4.rs index ba01e54bf5..327b38f3a7 100644 --- a/exercises/13_error_handling/errors4.rs +++ b/exercises/13_error_handling/errors4.rs @@ -10,7 +10,13 @@ struct PositiveNonzeroInteger(u64); impl PositiveNonzeroInteger { fn new(value: i64) -> Result { // TODO: This function shouldn't always return an `Ok`. - Ok(Self(value as u64)) + if value < 0 { + Err(CreationError::Negative) + } else if value == 0 { + Err(CreationError::Zero) + } else { + Ok(Self(value as u64)) + } } } diff --git a/exercises/13_error_handling/errors5.rs b/exercises/13_error_handling/errors5.rs index 125779b867..7b9019afbc 100644 --- a/exercises/13_error_handling/errors5.rs +++ b/exercises/13_error_handling/errors5.rs @@ -6,7 +6,7 @@ // // In short, this particular use case for boxes is for when you want to own a // value and you care only that it is a type which implements a particular -// trait. To do so, the `Box` is declared as of type `Box` where +// trait. To do so, The `Box` is declared as of type `Box` where // `Trait` is the trait the compiler looks for on any value used in that // context. For this exercise, that context is the potential errors which // can be returned in a `Result`. @@ -48,7 +48,7 @@ impl PositiveNonzeroInteger { // TODO: Add the correct return type `Result<(), Box>`. What can we // use to describe both errors? Is there a trait which both errors implement? -fn main() { +fn main() -> Result<(), Box> { let pretend_user_input = "42"; let x: i64 = pretend_user_input.parse()?; println!("output={:?}", PositiveNonzeroInteger::new(x)?); diff --git a/exercises/13_error_handling/errors6.rs b/exercises/13_error_handling/errors6.rs index b1995e036a..8ebb24f68c 100644 --- a/exercises/13_error_handling/errors6.rs +++ b/exercises/13_error_handling/errors6.rs @@ -26,6 +26,10 @@ impl ParsePosNonzeroError { // TODO: Add another error conversion function here. // fn from_parse_int(???) -> Self { ??? } + // 实现从 ParseIntError 转换成自定义错误的函数 + fn from_parse_int(err: ParseIntError) -> Self { + Self::ParseInt(err) + } } #[derive(PartialEq, Debug)] @@ -43,7 +47,7 @@ impl PositiveNonzeroInteger { fn parse(s: &str) -> Result { // TODO: change this to return an appropriate error instead of panicking // when `parse()` returns an error. - let x: i64 = s.parse().unwrap(); + let x: i64 = s.parse().map_err(ParsePosNonzeroError::from_parse_int)?; Self::new(x).map_err(ParsePosNonzeroError::from_creation) } } diff --git a/exercises/14_generics/generics1.rs b/exercises/14_generics/generics1.rs index 87ed990b65..e13fd828f1 100644 --- a/exercises/14_generics/generics1.rs +++ b/exercises/14_generics/generics1.rs @@ -6,7 +6,7 @@ fn main() { // TODO: Fix the compiler error by annotating the type of the vector // `Vec`. Choose `T` as some integer type that can be created from // `u8` and `i8`. - let mut numbers = Vec::new(); + let mut numbers: Vec = Vec::new(); // Don't change the lines below. let n1: u8 = 42; diff --git a/exercises/14_generics/generics2.rs b/exercises/14_generics/generics2.rs index 8908725bf9..b185f06ded 100644 --- a/exercises/14_generics/generics2.rs +++ b/exercises/14_generics/generics2.rs @@ -1,18 +1,24 @@ // This powerful wrapper provides the ability to store a positive integer value. // TODO: Rewrite it using a generic so that it supports wrapping ANY type. -struct Wrapper { - value: u32, +// 结构体本身加泛型参数 +struct Wrapper { + value: T, } // TODO: Adapt the struct's implementation to be generic over the wrapped value. -impl Wrapper { - fn new(value: u32) -> Self { +// 泛型实现 +impl Wrapper { + // 这里参数类型是 T,不是固定的 u32 + fn new(value: T) -> Self { Wrapper { value } } } fn main() { // You can optionally experiment here. + let w_num = Wrapper::new(42u32); + let w_str = Wrapper::new("Foo"); + println!("w_num = {}, w_str = {}", w_num.value, w_str.value); } #[cfg(test)] diff --git a/exercises/15_traits/traits1.rs b/exercises/15_traits/traits1.rs index 85be17ea82..c1f09642c5 100644 --- a/exercises/15_traits/traits1.rs +++ b/exercises/15_traits/traits1.rs @@ -6,6 +6,10 @@ trait AppendBar { impl AppendBar for String { // TODO: Implement `AppendBar` for the type `String`. + fn append_bar(mut self) -> Self { + self.push_str("Bar"); + self + } } fn main() { diff --git a/exercises/15_traits/traits2.rs b/exercises/15_traits/traits2.rs index d724dc288e..67a7da9465 100644 --- a/exercises/15_traits/traits2.rs +++ b/exercises/15_traits/traits2.rs @@ -4,6 +4,13 @@ trait AppendBar { // TODO: Implement the trait `AppendBar` for a vector of strings. // `append_bar` should push the string "Bar" into the vector. +// 为 Vec 实现 AppendBar +impl AppendBar for Vec { + fn append_bar(mut self) -> Self { + self.push(String::from("Bar")); + self + } +} fn main() { // You can optionally experiment here. diff --git a/exercises/15_traits/traits3.rs b/exercises/15_traits/traits3.rs index c244650da6..14823ff087 100644 --- a/exercises/15_traits/traits3.rs +++ b/exercises/15_traits/traits3.rs @@ -3,7 +3,10 @@ trait Licensed { // implementors like the two structs below can share that default behavior // without repeating the function. // The default license information should be the string "Default license". - fn licensing_info(&self) -> String; + // 提供默认实现 + fn licensing_info(&self) -> String { + String::from("Default license") + } } struct SomeSoftware { diff --git a/exercises/15_traits/traits4.rs b/exercises/15_traits/traits4.rs index 80092a6466..105837144c 100644 --- a/exercises/15_traits/traits4.rs +++ b/exercises/15_traits/traits4.rs @@ -11,7 +11,7 @@ impl Licensed for SomeSoftware {} impl Licensed for OtherSoftware {} // TODO: Fix the compiler error by only changing the signature of this function. -fn compare_license_types(software1: ???, software2: ???) -> bool { +fn compare_license_types(software1: T, software2: U) -> bool { software1.licensing_info() == software2.licensing_info() } diff --git a/exercises/15_traits/traits5.rs b/exercises/15_traits/traits5.rs index 5b356ac738..f2fbdb121d 100644 --- a/exercises/15_traits/traits5.rs +++ b/exercises/15_traits/traits5.rs @@ -19,7 +19,7 @@ impl SomeTrait for OtherStruct {} impl OtherTrait for OtherStruct {} // TODO: Fix the compiler error by only changing the signature of this function. -fn some_func(item: ???) -> bool { +fn some_func(item: T) -> bool { item.some_function() && item.other_function() } diff --git a/exercises/16_lifetimes/lifetimes1.rs b/exercises/16_lifetimes/lifetimes1.rs index 19e2d398b5..683bd75592 100644 --- a/exercises/16_lifetimes/lifetimes1.rs +++ b/exercises/16_lifetimes/lifetimes1.rs @@ -4,7 +4,7 @@ // not own their own data. What if their owner goes out of scope? // TODO: Fix the compiler error by updating the function signature. -fn longest(x: &str, y: &str) -> &str { +fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { diff --git a/exercises/16_lifetimes/lifetimes2.rs b/exercises/16_lifetimes/lifetimes2.rs index de5a5dfc79..853b63f88b 100644 --- a/exercises/16_lifetimes/lifetimes2.rs +++ b/exercises/16_lifetimes/lifetimes2.rs @@ -9,12 +9,8 @@ fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { fn main() { // TODO: Fix the compiler error by moving one line. - let string1 = String::from("long string is long"); - let result; - { - let string2 = String::from("xyz"); - result = longest(&string1, &string2); - } + let string2 = String::from("xyz"); // <-- 移出内层作用域 + let result = longest(&string1, &string2); println!("The longest string is '{result}'"); } diff --git a/exercises/16_lifetimes/lifetimes3.rs b/exercises/16_lifetimes/lifetimes3.rs index 1cc27592c6..91e3922c26 100644 --- a/exercises/16_lifetimes/lifetimes3.rs +++ b/exercises/16_lifetimes/lifetimes3.rs @@ -1,9 +1,9 @@ // Lifetimes are also needed when structs hold references. // TODO: Fix the compiler errors about the struct. -struct Book { - author: &str, - title: &str, +struct Book<'a> { + author: &'a str, + title: &'a str, } fn main() { diff --git a/exercises/17_tests/tests1.rs b/exercises/17_tests/tests1.rs index 7529f9f049..662c75c1b9 100644 --- a/exercises/17_tests/tests1.rs +++ b/exercises/17_tests/tests1.rs @@ -13,11 +13,13 @@ fn main() { mod tests { // TODO: Import `is_even`. You can use a wildcard to import everything in // the outer module. + // 导入外层模块的所有内容,包括 is_even + use super::*; #[test] fn you_can_assert() { // TODO: Test the function `is_even` with some values. - assert!(); - assert!(); + assert!(is_even(2)); // 2 是偶数,应该返回 true + assert!(!is_even(3)); // 3 是奇数,应该返回 false,所以加 ! } } diff --git a/exercises/17_tests/tests2.rs b/exercises/17_tests/tests2.rs index 0c6573e8f0..72719d712e 100644 --- a/exercises/17_tests/tests2.rs +++ b/exercises/17_tests/tests2.rs @@ -15,9 +15,9 @@ mod tests { #[test] fn you_can_assert_eq() { // TODO: Test the function `power_of_2` with some values. - assert_eq!(); - assert_eq!(); - assert_eq!(); - assert_eq!(); + assert_eq!(power_of_2(0), 1); // 2^0 = 1 + assert_eq!(power_of_2(1), 2); // 2^1 = 2 + assert_eq!(power_of_2(5), 32); // 2^5 = 32 + assert_eq!(power_of_2(10), 1024); // 2^10 = 1024 } } diff --git a/exercises/17_tests/tests3.rs b/exercises/17_tests/tests3.rs index 822184ef75..6a26826d12 100644 --- a/exercises/17_tests/tests3.rs +++ b/exercises/17_tests/tests3.rs @@ -29,21 +29,23 @@ mod tests { // TODO: This test should check if the rectangle has the size that we // pass to its constructor. let rect = Rectangle::new(10, 20); - assert_eq!(todo!(), 10); // Check width - assert_eq!(todo!(), 20); // Check height + assert_eq!(rect.width, 10); // 检查宽度 + assert_eq!(rect.height, 20); // 检查高度 } // TODO: This test should check if the program panics when we try to create // a rectangle with negative width. #[test] + #[should_panic(expected = "Rectangle width and height must be positive")] fn negative_width() { - let _rect = Rectangle::new(-10, 10); + Rectangle::new(-10, 10); } // TODO: This test should check if the program panics when we try to create // a rectangle with negative height. #[test] + #[should_panic(expected = "Rectangle width and height must be positive")] fn negative_height() { - let _rect = Rectangle::new(10, -10); + Rectangle::new(10, -10); } } diff --git a/exercises/18_iterators/iterators1.rs b/exercises/18_iterators/iterators1.rs index ca937ed00e..2b40ed3c42 100644 --- a/exercises/18_iterators/iterators1.rs +++ b/exercises/18_iterators/iterators1.rs @@ -12,14 +12,14 @@ mod tests { fn iterators() { let my_fav_fruits = ["banana", "custard apple", "avocado", "peach", "raspberry"]; - // TODO: Create an iterator over the array. - let mut fav_fruits_iterator = todo!(); + // 创建迭代器 + let mut fav_fruits_iterator = my_fav_fruits.iter(); assert_eq!(fav_fruits_iterator.next(), Some(&"banana")); - assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()` + assert_eq!(fav_fruits_iterator.next(), Some(&"custard apple")); assert_eq!(fav_fruits_iterator.next(), Some(&"avocado")); - assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()` + assert_eq!(fav_fruits_iterator.next(), Some(&"peach")); assert_eq!(fav_fruits_iterator.next(), Some(&"raspberry")); - assert_eq!(fav_fruits_iterator.next(), todo!()); // TODO: Replace `todo!()` + assert_eq!(fav_fruits_iterator.next(), None); } } diff --git a/exercises/18_iterators/iterators2.rs b/exercises/18_iterators/iterators2.rs index 5903e657e9..9a7482f5d8 100644 --- a/exercises/18_iterators/iterators2.rs +++ b/exercises/18_iterators/iterators2.rs @@ -7,7 +7,7 @@ fn capitalize_first(input: &str) -> String { let mut chars = input.chars(); match chars.next() { None => String::new(), - Some(first) => todo!(), + Some(first) => first.to_uppercase().collect::() + chars.as_str(), } } @@ -15,14 +15,18 @@ fn capitalize_first(input: &str) -> String { // Return a vector of strings. // ["hello", "world"] -> ["Hello", "World"] fn capitalize_words_vector(words: &[&str]) -> Vec { - // ??? + words.iter() + .map(|word| capitalize_first(word)) + .collect() } // TODO: Apply the `capitalize_first` function again to a slice of string // slices. Return a single string. // ["hello", " ", "world"] -> "Hello World" fn capitalize_words_string(words: &[&str]) -> String { - // ??? + words.iter() + .map(|word| capitalize_first(word)) + .collect::() } fn main() { diff --git a/exercises/18_iterators/iterators3.rs b/exercises/18_iterators/iterators3.rs index 6b1eca1734..d4ce1a4abb 100644 --- a/exercises/18_iterators/iterators3.rs +++ b/exercises/18_iterators/iterators3.rs @@ -1,33 +1,44 @@ #[derive(Debug, PartialEq, Eq)] enum DivisionError { - // Example: 42 / 0 DivideByZero, - // Only case for `i64`: `i64::MIN / -1` because the result is `i64::MAX + 1` IntegerOverflow, - // Example: 5 / 2 = 2.5 NotDivisible, + } // TODO: Calculate `a` divided by `b` if `a` is evenly divisible by `b`. // Otherwise, return a suitable error. fn divide(a: i64, b: i64) -> Result { - todo!(); + if b == 0 { + return Err(DivisionError::DivideByZero); + } + if a == i64::MIN && b == -1 { + return Err(DivisionError::IntegerOverflow); + } + if a % b != 0 { + return Err(DivisionError::NotDivisible); + } + Ok(a / b) } // TODO: Add the correct return type and complete the function body. // Desired output: `Ok([1, 11, 1426, 3])` -fn result_with_list() { +// 返回 Result 包裹的 Vec,遇错即返回 Err +fn result_with_list() -> Result, DivisionError> { let numbers = [27, 297, 38502, 81]; - let division_results = numbers.into_iter().map(|n| divide(n, 27)); + numbers.iter().map(|&n| divide(n, 27)).collect() } + // TODO: Add the correct return type and complete the function body. // Desired output: `[Ok(1), Ok(11), Ok(1426), Ok(3)]` -fn list_of_results() { +// 返回 Vec 中每个元素是 Result,保存所有结果 +fn list_of_results() -> Vec> { let numbers = [27, 297, 38502, 81]; - let division_results = numbers.into_iter().map(|n| divide(n, 27)); + numbers.iter().map(|&n| divide(n, 27)).collect() } + fn main() { // You can optionally experiment here. } diff --git a/exercises/18_iterators/iterators4.rs b/exercises/18_iterators/iterators4.rs index c296f0e426..2869874dd6 100644 --- a/exercises/18_iterators/iterators4.rs +++ b/exercises/18_iterators/iterators4.rs @@ -10,6 +10,7 @@ fn factorial(num: u64) -> u64 { // - additional variables // For an extra challenge, don't use: // - recursion + (1..=num).fold(1, |acc, x| acc * x) } fn main() { diff --git a/exercises/18_iterators/iterators5.rs b/exercises/18_iterators/iterators5.rs index 7e434cc5f9..50aa0b56a2 100644 --- a/exercises/18_iterators/iterators5.rs +++ b/exercises/18_iterators/iterators5.rs @@ -28,6 +28,9 @@ fn count_for(map: &HashMap, value: Progress) -> usize { fn count_iterator(map: &HashMap, value: Progress) -> usize { // `map` is a hash map with `String` keys and `Progress` values. // map = { "variables1": Complete, "from_str": None, … } + map.values() + .filter(|&&val| val == value) + .count() } fn count_collection_for(collection: &[HashMap], value: Progress) -> usize { @@ -48,6 +51,10 @@ fn count_collection_iterator(collection: &[HashMap], value: Pr // `collection` is a slice of hash maps. // collection = [{ "variables1": Complete, "from_str": None, … }, // { "variables2": Complete, … }, … ] + collection.iter() + .flat_map(|map| map.values()) + .filter(|&&val| val == value) + .count() } fn main() { diff --git a/exercises/19_smart_pointers/arc1.rs b/exercises/19_smart_pointers/arc1.rs index 6bb860f93f..c8d687c54d 100644 --- a/exercises/19_smart_pointers/arc1.rs +++ b/exercises/19_smart_pointers/arc1.rs @@ -24,12 +24,14 @@ fn main() { // TODO: Define `shared_numbers` by using `Arc`. // let shared_numbers = ???; + let shared_numbers = Arc::new(numbers); let mut join_handles = Vec::new(); for offset in 0..8 { // TODO: Define `child_numbers` using `shared_numbers`. // let child_numbers = ???; + let child_numbers = Arc::clone(&shared_numbers); let handle = thread::spawn(move || { let sum: u32 = child_numbers.iter().filter(|&&n| n % 8 == offset).sum(); diff --git a/exercises/19_smart_pointers/box1.rs b/exercises/19_smart_pointers/box1.rs index d70e1c3d39..7f062c49bf 100644 --- a/exercises/19_smart_pointers/box1.rs +++ b/exercises/19_smart_pointers/box1.rs @@ -12,18 +12,22 @@ // TODO: Use a `Box` in the enum definition to make the code compile. #[derive(PartialEq, Debug)] enum List { - Cons(i32, List), + Cons(i32, Box), // 用 Box 包裹 List 类型 Nil, } // TODO: Create an empty cons list. fn create_empty_list() -> List { - todo!() + List::Nil } // TODO: Create a non-empty cons list. fn create_non_empty_list() -> List { - todo!() + List::Cons(1, Box::new( + List::Cons(2, Box::new( + List::Cons(3, Box::new(List::Nil)) + )) + )) } fn main() { diff --git a/exercises/19_smart_pointers/cow1.rs b/exercises/19_smart_pointers/cow1.rs index 1566500716..f7bdfe8a01 100644 --- a/exercises/19_smart_pointers/cow1.rs +++ b/exercises/19_smart_pointers/cow1.rs @@ -39,7 +39,8 @@ mod tests { let mut input = Cow::from(&vec); abs_all(&mut input); // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`. - assert!(matches!(input, todo!())); + // 没有发生修改,也没有触发克隆,依然是 Borrowed + assert!(matches!(input, Cow::Borrowed(_))); } #[test] @@ -52,7 +53,8 @@ mod tests { let mut input = Cow::from(vec); abs_all(&mut input); // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`. - assert!(matches!(input, todo!())); + // 传入 Owned,且发生了修改,依然是 Owned + assert!(matches!(input, Cow::Owned(_))); } #[test] @@ -64,6 +66,6 @@ mod tests { let mut input = Cow::from(vec); abs_all(&mut input); // TODO: Replace `todo!()` with `Cow::Owned(_)` or `Cow::Borrowed(_)`. - assert!(matches!(input, todo!())); + assert!(matches!(input, Cow::Owned(_))); } } diff --git a/exercises/19_smart_pointers/rc1.rs b/exercises/19_smart_pointers/rc1.rs index ecd3438701..5c9ce8465e 100644 --- a/exercises/19_smart_pointers/rc1.rs +++ b/exercises/19_smart_pointers/rc1.rs @@ -60,17 +60,17 @@ mod tests { jupiter.details(); // TODO - let saturn = Planet::Saturn(Rc::new(Sun)); + let saturn = Planet::Saturn(Rc::clone(&sun)); println!("reference count = {}", Rc::strong_count(&sun)); // 7 references saturn.details(); // TODO - let uranus = Planet::Uranus(Rc::new(Sun)); + let uranus = Planet::Uranus(Rc::clone(&sun)); println!("reference count = {}", Rc::strong_count(&sun)); // 8 references uranus.details(); // TODO - let neptune = Planet::Neptune(Rc::new(Sun)); + let neptune = Planet::Neptune(Rc::clone(&sun)); println!("reference count = {}", Rc::strong_count(&sun)); // 9 references neptune.details(); @@ -92,12 +92,15 @@ mod tests { println!("reference count = {}", Rc::strong_count(&sun)); // 4 references // TODO + drop(earth); println!("reference count = {}", Rc::strong_count(&sun)); // 3 references // TODO + drop(venus); println!("reference count = {}", Rc::strong_count(&sun)); // 2 references // TODO + drop(mercury); println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference assert_eq!(Rc::strong_count(&sun), 1); diff --git a/exercises/20_threads/threads1.rs b/exercises/20_threads/threads1.rs index dbc64b1644..743964306c 100644 --- a/exercises/20_threads/threads1.rs +++ b/exercises/20_threads/threads1.rs @@ -24,6 +24,8 @@ fn main() { for handle in handles { // TODO: Collect the results of all threads into the `results` vector. // Use the `JoinHandle` struct which is returned by `thread::spawn`. + let result = handle.join().expect("Thread panicked"); + results.push(result); } if results.len() != 10 { diff --git a/exercises/20_threads/threads2.rs b/exercises/20_threads/threads2.rs index 7020cb9cea..d9b5cb752c 100644 --- a/exercises/20_threads/threads2.rs +++ b/exercises/20_threads/threads2.rs @@ -3,6 +3,7 @@ // shared value: `JobStatus.jobs_done` use std::{sync::Arc, thread, time::Duration}; +use std::sync::{Mutex}; struct JobStatus { jobs_done: u32, @@ -10,7 +11,7 @@ struct JobStatus { fn main() { // TODO: `Arc` isn't enough if you want a **mutable** shared state. - let status = Arc::new(JobStatus { jobs_done: 0 }); + let status = Arc::new(Mutex::new(JobStatus { jobs_done: 0 })); let mut handles = Vec::new(); for _ in 0..10 { @@ -19,7 +20,8 @@ fn main() { thread::sleep(Duration::from_millis(250)); // TODO: You must take an action before you update a shared value. - status_shared.jobs_done += 1; + let mut status = status_shared.lock().unwrap(); + status.jobs_done += 1; }); handles.push(handle); } @@ -30,5 +32,5 @@ fn main() { } // TODO: Print the value of `JobStatus.jobs_done`. - println!("Jobs done: {}", todo!()); + println!("Jobs done: {}", status.lock().unwrap().jobs_done); } diff --git a/exercises/20_threads/threads3.rs b/exercises/20_threads/threads3.rs index 6d16bd9fec..4e30f9c563 100644 --- a/exercises/20_threads/threads3.rs +++ b/exercises/20_threads/threads3.rs @@ -17,10 +17,13 @@ impl Queue { fn send_tx(q: Queue, tx: mpsc::Sender) { // TODO: We want to send `tx` to both threads. But currently, it is moved // into the first thread. How could you solve this problem? + let tx1 = tx.clone(); // 克隆一个发送者给第一个线程 + let tx2 = tx; // 原发送者给第二个线程 + thread::spawn(move || { for val in q.first_half { println!("Sending {val:?}"); - tx.send(val).unwrap(); + tx1.send(val).unwrap(); thread::sleep(Duration::from_millis(250)); } }); @@ -28,7 +31,7 @@ fn send_tx(q: Queue, tx: mpsc::Sender) { thread::spawn(move || { for val in q.second_half { println!("Sending {val:?}"); - tx.send(val).unwrap(); + tx2.send(val).unwrap(); thread::sleep(Duration::from_millis(250)); } }); diff --git a/exercises/21_macros/README.md b/exercises/21_macros/README.md index de7fb7ba3b..337816d6e6 100644 --- a/exercises/21_macros/README.md +++ b/exercises/21_macros/README.md @@ -10,6 +10,5 @@ of exercises to Rustlings, but is all about learning to write Macros. ## Further information -- [The Rust Book - Macros](https://doc.rust-lang.org/book/ch20-05-macros.html) +- [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html) - [The Little Book of Rust Macros](https://veykril.github.io/tlborm/) -- [Rust by Example - macro_rules!](https://doc.rust-lang.org/rust-by-example/macros.html) diff --git a/exercises/21_macros/macros1.rs b/exercises/21_macros/macros1.rs index fb3c3ff9b3..fb550f9d61 100644 --- a/exercises/21_macros/macros1.rs +++ b/exercises/21_macros/macros1.rs @@ -6,5 +6,5 @@ macro_rules! my_macro { fn main() { // TODO: Fix the macro call. - my_macro(); + my_macro!(); } diff --git a/exercises/21_macros/macros2.rs b/exercises/21_macros/macros2.rs index 2d9dec76ca..b2b5553cbf 100644 --- a/exercises/21_macros/macros2.rs +++ b/exercises/21_macros/macros2.rs @@ -1,6 +1,3 @@ -fn main() { - my_macro!(); -} // TODO: Fix the compiler error by moving the whole definition of this macro. macro_rules! my_macro { @@ -8,3 +5,7 @@ macro_rules! my_macro { println!("Check out my macro!"); }; } + +fn main() { + my_macro!(); +} diff --git a/exercises/21_macros/macros3.rs b/exercises/21_macros/macros3.rs index 95374948be..7b2e72b6df 100644 --- a/exercises/21_macros/macros3.rs +++ b/exercises/21_macros/macros3.rs @@ -1,6 +1,7 @@ // TODO: Fix the compiler error without taking the macro definition out of this // module. mod macros { + #[macro_export] macro_rules! my_macro { () => { println!("Check out my macro!"); diff --git a/exercises/21_macros/macros4.rs b/exercises/21_macros/macros4.rs index 9d77f6a5c8..3396f0d3dd 100644 --- a/exercises/21_macros/macros4.rs +++ b/exercises/21_macros/macros4.rs @@ -3,7 +3,7 @@ macro_rules! my_macro { () => { println!("Check out my macro!"); - } + }; ($val:expr) => { println!("Look at this other macro: {}", $val); } diff --git a/exercises/22_clippy/clippy1.rs b/exercises/22_clippy/clippy1.rs index 7165da4559..01d3ce7e7f 100644 --- a/exercises/22_clippy/clippy1.rs +++ b/exercises/22_clippy/clippy1.rs @@ -6,7 +6,7 @@ fn main() { // TODO: Fix the Clippy lint in this line. - let pi = 3.14; + let pi = std::f32::consts::PI; // 使用标准库的圆周率常量 let radius: f32 = 5.0; let area = pi * radius.powi(2); diff --git a/exercises/22_clippy/clippy2.rs b/exercises/22_clippy/clippy2.rs index 8cfe6f80a2..c0533ed8ff 100644 --- a/exercises/22_clippy/clippy2.rs +++ b/exercises/22_clippy/clippy2.rs @@ -2,7 +2,7 @@ fn main() { let mut res = 42; let option = Some(12); // TODO: Fix the Clippy lint. - for x in option { + if let Some(x) = option { res += x; } diff --git a/exercises/22_clippy/clippy3.rs b/exercises/22_clippy/clippy3.rs index 7a3cb39006..64a65b9097 100644 --- a/exercises/22_clippy/clippy3.rs +++ b/exercises/22_clippy/clippy3.rs @@ -4,26 +4,29 @@ #[rustfmt::skip] #[allow(unused_variables, unused_assignments)] fn main() { - let my_option: Option<&str> = None; - // Assume that you don't know the value of `my_option`. - // In the case of `Some`, we want to print its value. + // 1. 用 unwrap() 之前没有先确认 Option 是 Some,会 panic。且 if my_option.is_none() 时,调用 unwrap() 是错误的。 + // Clippy 建议用 match 或 if let 结构。 + let my_option: Option<()> = None; if my_option.is_none() { - println!("{}", my_option.unwrap()); + // 这里 unwrap() 会 panic,改成打印 None 即可 + println!("{:?}", my_option); } + // 2. 数组定义语法错误,缺少逗号分隔元素 let my_arr = &[ - -1, -2, -3 - -4, -5, -6 + -1, -2, -3, + -4, -5, -6, ]; println!("My array! Here it is: {my_arr:?}"); - let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5); + // 3. vec![].resize() 返回的是 (), 不能赋值给变量 + let mut my_empty_vec = vec![1, 2, 3, 4, 5]; + my_empty_vec.clear(); println!("This Vec is empty, see? {my_empty_vec:?}"); + // 4. 交换两个变量的值,Clippy 建议用 std::mem::swap let mut value_a = 45; let mut value_b = 66; - // Let's swap these two! - value_a = value_b; - value_b = value_a; + std::mem::swap(&mut value_a, &mut value_b); println!("value a: {value_a}; value b: {value_b}"); } diff --git a/exercises/23_conversions/as_ref_mut.rs b/exercises/23_conversions/as_ref_mut.rs index d7892dd490..ecb3b06b9a 100644 --- a/exercises/23_conversions/as_ref_mut.rs +++ b/exercises/23_conversions/as_ref_mut.rs @@ -5,20 +5,24 @@ // Obtain the number of bytes (not characters) in the given argument // (`.len()` returns the number of bytes in a string). // TODO: Add the `AsRef` trait appropriately as a trait bound. -fn byte_counter(arg: T) -> usize { +fn byte_counter>(arg: T) -> usize { arg.as_ref().len() } // Obtain the number of characters (not bytes) in the given argument. // TODO: Add the `AsRef` trait appropriately as a trait bound. -fn char_counter(arg: T) -> usize { +fn char_counter>(arg: T) -> usize { arg.as_ref().chars().count() } // Squares a number using `as_mut()`. // TODO: Add the appropriate trait bound. -fn num_sq(arg: &mut T) { - // TODO: Implement the function body. +fn num_sq(arg: &mut T) +where + T: AsMut, +{ + let val = arg.as_mut(); + *val = (*val) * (*val); } fn main() { diff --git a/exercises/23_conversions/from_into.rs b/exercises/23_conversions/from_into.rs index bc2783a30f..111a3abeb3 100644 --- a/exercises/23_conversions/from_into.rs +++ b/exercises/23_conversions/from_into.rs @@ -34,7 +34,34 @@ impl Default for Person { // 5. Parse the second element from the split operation into a `u8` as the age. // 6. If parsing the age fails, return the default of `Person`. impl From<&str> for Person { - fn from(s: &str) -> Self {} + fn from(s: &str) -> Self { + // 1. 按逗号分割 + let parts: Vec<&str> = s.split(',').collect(); + // 2. 如果分割结果不等于2,返回默认 + if parts.len() != 2 { + return Person::default(); + } + + let name = parts[0].trim(); + let age_str = parts[1].trim(); + + // 3. 如果名字为空,返回默认 + if name.is_empty() { + return Person::default(); + } + + // 4. 尝试解析年龄 + let age = match age_str.parse::() { + Ok(a) => a, + Err(_) => return Person::default(), + }; + + // 5. 构造 Person + Person { + name: name.to_string(), + age, + } + } } fn main() { diff --git a/exercises/23_conversions/from_str.rs b/exercises/23_conversions/from_str.rs index ec6d3fd129..e27bc76a32 100644 --- a/exercises/23_conversions/from_str.rs +++ b/exercises/23_conversions/from_str.rs @@ -41,7 +41,31 @@ enum ParsePersonError { impl FromStr for Person { type Err = ParsePersonError; - fn from_str(s: &str) -> Result {} + fn from_str(s: &str) -> Result { + // 1. 按逗号分割 + let parts: Vec<&str> = s.split(',').collect(); + + // 2. 判断数量 + if parts.len() != 2 { + return Err(ParsePersonError::BadLen); + } + + let name = parts[0].trim(); + let age_str = parts[1].trim(); + + // 3. 名字非空判断 + if name.is_empty() { + return Err(ParsePersonError::NoName); + } + + // 4. 尝试解析年龄,解析失败要包装错误返回 + let age: u8 = age_str.parse().map_err(ParsePersonError::ParseInt)?; + + Ok(Person { + name: name.to_string(), + age, + }) + } } fn main() { diff --git a/exercises/23_conversions/try_from_into.rs b/exercises/23_conversions/try_from_into.rs index f3ae80a9e4..04ecebd1fd 100644 --- a/exercises/23_conversions/try_from_into.rs +++ b/exercises/23_conversions/try_from_into.rs @@ -25,17 +25,34 @@ enum IntoColorError { // TODO: Tuple implementation. // Correct RGB color values must be integers in the 0..=255 range. +fn check_range(value: i16) -> Result { + if (0..=255).contains(&value) { + Ok(value as u8) + } else { + Err(IntoColorError::IntConversion) + } +} + impl TryFrom<(i16, i16, i16)> for Color { type Error = IntoColorError; - fn try_from(tuple: (i16, i16, i16)) -> Result {} + fn try_from(tuple: (i16, i16, i16)) -> Result { + Ok(Color { + red: check_range(tuple.0)?, + green: check_range(tuple.1)?, + blue: check_range(tuple.2)?, + }) + } } // TODO: Array implementation. impl TryFrom<[i16; 3]> for Color { type Error = IntoColorError; - fn try_from(arr: [i16; 3]) -> Result {} + fn try_from(arr: [i16; 3]) -> Result { + // 直接复用元组实现的逻辑 + Color::try_from((arr[0], arr[1], arr[2])) + } } // TODO: Slice implementation. @@ -43,7 +60,12 @@ impl TryFrom<[i16; 3]> for Color { impl TryFrom<&[i16]> for Color { type Error = IntoColorError; - fn try_from(slice: &[i16]) -> Result {} + fn try_from(slice: &[i16]) -> Result { + if slice.len() != 3 { + return Err(IntoColorError::BadLen); + } + Color::try_from((slice[0], slice[1], slice[2])) + } } fn main() { diff --git a/exercises/23_conversions/using_as.rs b/exercises/23_conversions/using_as.rs index c131d1f32f..dff453b202 100644 --- a/exercises/23_conversions/using_as.rs +++ b/exercises/23_conversions/using_as.rs @@ -5,7 +5,7 @@ fn average(values: &[f64]) -> f64 { let total = values.iter().sum::(); // TODO: Make a conversion before dividing. - total / values.len() + total / values.len() as f64 } fn main() { diff --git a/exercises/quizzes/quiz1.rs b/exercises/quizzes/quiz1.rs index 04fb2aaf8d..f38953d6d0 100644 --- a/exercises/quizzes/quiz1.rs +++ b/exercises/quizzes/quiz1.rs @@ -11,9 +11,17 @@ // TODO: Write a function that calculates the price of an order of apples given // the quantity bought. // fn calculate_price_of_apples(???) -> ??? { ??? } - +fn calculate_price_of_apples(quantity: usize) -> usize { + if quantity > 40 { + quantity // 每个1 rustbuck + } else { + quantity * 2 // 每个2 rustbucks + } +} fn main() { // You can optionally experiment here. + println!("{}", calculate_price_of_apples(35)); // 70 + println!("{}", calculate_price_of_apples(41)); // 41 } // Don't change the tests! diff --git a/exercises/quizzes/quiz2.rs b/exercises/quizzes/quiz2.rs index 2cddba907e..56a8ef68e7 100644 --- a/exercises/quizzes/quiz2.rs +++ b/exercises/quizzes/quiz2.rs @@ -28,6 +28,20 @@ mod my_module { // TODO: Complete the function as described above. // pub fn transformer(input: ???) -> ??? { ??? } + pub fn transformer(input: Vec<(String, Command)>) -> Vec { + input.into_iter().map(|(mut s, cmd)| { + match cmd { + Command::Uppercase => s.to_uppercase(), + Command::Trim => s.trim().to_string(), + Command::Append(n) => { + for _ in 0..n { + s.push_str("bar"); + } + s + } + } + }).collect() + } } fn main() { @@ -39,6 +53,7 @@ mod tests { // TODO: What do we need to import to have `transformer` in scope? // use ???; use super::Command; + use crate::my_module::transformer; #[test] fn it_works() { diff --git a/exercises/quizzes/quiz3.rs b/exercises/quizzes/quiz3.rs index c877c5f8e6..d22334c7ba 100644 --- a/exercises/quizzes/quiz3.rs +++ b/exercises/quizzes/quiz3.rs @@ -12,24 +12,38 @@ // block to support alphabetical report cards in addition to numerical ones. // TODO: Adjust the struct as described above. -struct ReportCard { - grade: f32, +use std::fmt::Display; +struct ReportCard { + grade: T, student_name: String, student_age: u8, } // TODO: Adjust the impl block as described above. -impl ReportCard { +impl ReportCard { fn print(&self) -> String { format!( "{} ({}) - achieved a grade of {}", - &self.student_name, &self.student_age, &self.grade, + self.student_name, self.student_age, self.grade ) } } fn main() { // You can optionally experiment here. + let numeric = ReportCard { + grade: 2.1, + student_name: "Tom Wriggle".to_string(), + student_age: 12, + }; + println!("{}", numeric.print()); + + let alphabetic = ReportCard { + grade: "A+".to_string(), + student_name: "Gary Plotter".to_string(), + student_age: 11, + }; + println!("{}", alphabetic.print()); } #[cfg(test)] From a6464c63e2d047b806f669ddf2557b2719c609a3 Mon Sep 17 00:00:00 2001 From: GaoJie Date: Wed, 6 Aug 2025 19:29:56 +0800 Subject: [PATCH 02/10] hashmaps2 --- exercises/11_hashmaps/hashmaps2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/11_hashmaps/hashmaps2.rs b/exercises/11_hashmaps/hashmaps2.rs index cc136306d5..606b4c44de 100644 --- a/exercises/11_hashmaps/hashmaps2.rs +++ b/exercises/11_hashmaps/hashmaps2.rs @@ -33,7 +33,7 @@ fn fruit_basket(basket: &mut HashMap) { // basket. Note that you are not allowed to put any type of fruit that's // already present! if !basket.contains_key(&fruit) { - basket.insert(fruit, 1); + basket.insert(fruit, 2); } } } From b56a30d87812d09775273b3a842b128bafcaf08f Mon Sep 17 00:00:00 2001 From: GaoJie Date: Wed, 6 Aug 2025 20:35:09 +0800 Subject: [PATCH 03/10] correct hashmaps2 and threads3 --- exercises/11_hashmaps/hashmaps2.rs | 1 + exercises/20_threads/threads3.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/exercises/11_hashmaps/hashmaps2.rs b/exercises/11_hashmaps/hashmaps2.rs index 606b4c44de..318db92765 100644 --- a/exercises/11_hashmaps/hashmaps2.rs +++ b/exercises/11_hashmaps/hashmaps2.rs @@ -9,6 +9,7 @@ // Mango, and Lychee). use std::collections::HashMap; +use std::iter::FromIterator; #[derive(Hash, PartialEq, Eq, Debug)] enum Fruit { diff --git a/exercises/20_threads/threads3.rs b/exercises/20_threads/threads3.rs index 4e30f9c563..fd9187e7ca 100644 --- a/exercises/20_threads/threads3.rs +++ b/exercises/20_threads/threads3.rs @@ -17,8 +17,8 @@ impl Queue { fn send_tx(q: Queue, tx: mpsc::Sender) { // TODO: We want to send `tx` to both threads. But currently, it is moved // into the first thread. How could you solve this problem? - let tx1 = tx.clone(); // 克隆一个发送者给第一个线程 - let tx2 = tx; // 原发送者给第二个线程 + let first_half = q.first_half; + let second_half = q.second_half; thread::spawn(move || { for val in q.first_half { From b04f5c6289ba3b2bb1f466c38ce958989355833e Mon Sep 17 00:00:00 2001 From: GaoJie Date: Wed, 6 Aug 2025 20:39:54 +0800 Subject: [PATCH 04/10] thread3 --- exercises/20_threads/threads3.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/exercises/20_threads/threads3.rs b/exercises/20_threads/threads3.rs index fd9187e7ca..b0808f1890 100644 --- a/exercises/20_threads/threads3.rs +++ b/exercises/20_threads/threads3.rs @@ -20,8 +20,12 @@ fn send_tx(q: Queue, tx: mpsc::Sender) { let first_half = q.first_half; let second_half = q.second_half; + // 克隆两个发送者 + let tx1 = tx.clone(); + let tx2 = tx; + thread::spawn(move || { - for val in q.first_half { + for val in first_half { println!("Sending {val:?}"); tx1.send(val).unwrap(); thread::sleep(Duration::from_millis(250)); @@ -29,7 +33,7 @@ fn send_tx(q: Queue, tx: mpsc::Sender) { }); thread::spawn(move || { - for val in q.second_half { + for val in second_half { println!("Sending {val:?}"); tx2.send(val).unwrap(); thread::sleep(Duration::from_millis(250)); From 9d05cbc3c501a4d0c838e6e7f1ba92edf3f86c57 Mon Sep 17 00:00:00 2001 From: GaoJie Date: Wed, 6 Aug 2025 20:59:03 +0800 Subject: [PATCH 05/10] clippy3 --- exercises/22_clippy/clippy3.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/exercises/22_clippy/clippy3.rs b/exercises/22_clippy/clippy3.rs index 64a65b9097..333c0e2317 100644 --- a/exercises/22_clippy/clippy3.rs +++ b/exercises/22_clippy/clippy3.rs @@ -4,29 +4,26 @@ #[rustfmt::skip] #[allow(unused_variables, unused_assignments)] fn main() { - // 1. 用 unwrap() 之前没有先确认 Option 是 Some,会 panic。且 if my_option.is_none() 时,调用 unwrap() 是错误的。 - // Clippy 建议用 match 或 if let 结构。 + // 1. 安全处理 Option,不再调用 unwrap() let my_option: Option<()> = None; - if my_option.is_none() { - // 这里 unwrap() 会 panic,改成打印 None 即可 - println!("{:?}", my_option); + if let Some(v) = my_option { + println!("Got value: {:?}", v); + } else { + println!("Got None!"); } - // 2. 数组定义语法错误,缺少逗号分隔元素 - let my_arr = &[ - -1, -2, -3, - -4, -5, -6, - ]; - println!("My array! Here it is: {my_arr:?}"); + // 2. 数组语法已正确,无需变动 + let my_arr = &[-1, -2, -3, -4, -5, -6]; + println!("My array! Here it is: {:?}", my_arr); - // 3. vec![].resize() 返回的是 (), 不能赋值给变量 + // 3. 清空 Vec,不需要捕获返回值 let mut my_empty_vec = vec![1, 2, 3, 4, 5]; - my_empty_vec.clear(); - println!("This Vec is empty, see? {my_empty_vec:?}"); + my_empty_vec.clear(); // .resize() 返回 (),不赋值给变量 + println!("This Vec is empty, see? {:?}", my_empty_vec); - // 4. 交换两个变量的值,Clippy 建议用 std::mem::swap + // 4. 使用 std::mem::swap let mut value_a = 45; let mut value_b = 66; std::mem::swap(&mut value_a, &mut value_b); - println!("value a: {value_a}; value b: {value_b}"); + println!("value a: {}; value b: {}", value_a, value_b); } From 48d5e618229ee17db67110e805e927ce01faf9ec Mon Sep 17 00:00:00 2001 From: GaoJie Date: Wed, 6 Aug 2025 21:14:29 +0800 Subject: [PATCH 06/10] clippy3 move on --- exercises/22_clippy/clippy3.rs | 37 +++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/exercises/22_clippy/clippy3.rs b/exercises/22_clippy/clippy3.rs index 333c0e2317..c277553237 100644 --- a/exercises/22_clippy/clippy3.rs +++ b/exercises/22_clippy/clippy3.rs @@ -4,26 +4,35 @@ #[rustfmt::skip] #[allow(unused_variables, unused_assignments)] fn main() { - // 1. 安全处理 Option,不再调用 unwrap() - let my_option: Option<()> = None; - if let Some(v) = my_option { - println!("Got value: {:?}", v); + let my_option: Option<&str> = None; + // Assume that you don't know the value of `my_option`. + // In the case of `Some`, we want to print its value. + // 安全地处理 Option + if let Some(val) = my_option { + println!("{}", val); } else { println!("Got None!"); } + // if my_option.is_none() { + // println!("{}", my_option.unwrap()); + // } - // 2. 数组语法已正确,无需变动 - let my_arr = &[-1, -2, -3, -4, -5, -6]; - println!("My array! Here it is: {:?}", my_arr); + let my_arr = &[ + -1, -2, -3 + -4, -5, -6 + ]; + println!("My array! Here it is: {my_arr:?}"); - // 3. 清空 Vec,不需要捕获返回值 + // let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5); let mut my_empty_vec = vec![1, 2, 3, 4, 5]; - my_empty_vec.clear(); // .resize() 返回 (),不赋值给变量 - println!("This Vec is empty, see? {:?}", my_empty_vec); + my_empty_vec.resize(0, 5); // 或 my_empty_vec.clear(); + println!("This Vec is empty, see? {my_empty_vec:?}"); - // 4. 使用 std::mem::swap let mut value_a = 45; let mut value_b = 66; - std::mem::swap(&mut value_a, &mut value_b); - println!("value a: {}; value b: {}", value_a, value_b); -} + // Let's swap these two! + td::mem::swap(&mut value_a, &mut value_b); + // value_a = value_b; + // value_b = value_a; + println!("value a: {value_a}; value b: {value_b}"); +} \ No newline at end of file From d7c6ad91f094c9fb693f90dd8aff781c9ec2d4b6 Mon Sep 17 00:00:00 2001 From: GaoJie Date: Wed, 6 Aug 2025 21:19:15 +0800 Subject: [PATCH 07/10] clippy3 pass --- exercises/22_clippy/clippy3.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/22_clippy/clippy3.rs b/exercises/22_clippy/clippy3.rs index c277553237..da94518f38 100644 --- a/exercises/22_clippy/clippy3.rs +++ b/exercises/22_clippy/clippy3.rs @@ -18,7 +18,7 @@ fn main() { // } let my_arr = &[ - -1, -2, -3 + -1, -2, -3, // 不能没有逗号 -4, -5, -6 ]; println!("My array! Here it is: {my_arr:?}"); @@ -31,7 +31,7 @@ fn main() { let mut value_a = 45; let mut value_b = 66; // Let's swap these two! - td::mem::swap(&mut value_a, &mut value_b); + std::mem::swap(&mut value_a, &mut value_b); // value_a = value_b; // value_b = value_a; println!("value a: {value_a}; value b: {value_b}"); From e953e5de01c9a00201b2e45f6a43e528abe9750b Mon Sep 17 00:00:00 2001 From: GaoJie Date: Wed, 6 Aug 2025 21:24:41 +0800 Subject: [PATCH 08/10] clippy3 pass --- exercises/22_clippy/clippy3.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exercises/22_clippy/clippy3.rs b/exercises/22_clippy/clippy3.rs index da94518f38..0ce0aa0316 100644 --- a/exercises/22_clippy/clippy3.rs +++ b/exercises/22_clippy/clippy3.rs @@ -4,7 +4,8 @@ #[rustfmt::skip] #[allow(unused_variables, unused_assignments)] fn main() { - let my_option: Option<&str> = None; + // let my_option: Option<&str> = None; + let my_option: Option<()> = None; // Assume that you don't know the value of `my_option`. // In the case of `Some`, we want to print its value. // 安全地处理 Option From aabaff3e8dd446f34b7e864f80628c8bd5e22ea2 Mon Sep 17 00:00:00 2001 From: GaoJie Date: Wed, 6 Aug 2025 21:31:01 +0800 Subject: [PATCH 09/10] clippy3 pass --- exercises/22_clippy/clippy3.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/exercises/22_clippy/clippy3.rs b/exercises/22_clippy/clippy3.rs index 0ce0aa0316..cf5ceeb2d5 100644 --- a/exercises/22_clippy/clippy3.rs +++ b/exercises/22_clippy/clippy3.rs @@ -9,10 +9,8 @@ fn main() { // Assume that you don't know the value of `my_option`. // In the case of `Some`, we want to print its value. // 安全地处理 Option - if let Some(val) = my_option { - println!("{}", val); - } else { - println!("Got None!"); + if my_option.is_none() { + println!("{my_option:?}"); } // if my_option.is_none() { // println!("{}", my_option.unwrap()); From 2df0b1acce893bd4d9120569480bc5df476e6a69 Mon Sep 17 00:00:00 2001 From: GaoJie Date: Wed, 6 Aug 2025 21:36:40 +0800 Subject: [PATCH 10/10] clippy3 pass --- exercises/22_clippy/clippy3.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/22_clippy/clippy3.rs b/exercises/22_clippy/clippy3.rs index cf5ceeb2d5..19b0f0b03e 100644 --- a/exercises/22_clippy/clippy3.rs +++ b/exercises/22_clippy/clippy3.rs @@ -24,7 +24,7 @@ fn main() { // let my_empty_vec = vec![1, 2, 3, 4, 5].resize(0, 5); let mut my_empty_vec = vec![1, 2, 3, 4, 5]; - my_empty_vec.resize(0, 5); // 或 my_empty_vec.clear(); + my_empty_vec.clear(); println!("This Vec is empty, see? {my_empty_vec:?}"); let mut value_a = 45;