找回密码
 立即注册
首页 资源区 代码 rustlings 学习随笔

rustlings 学习随笔

缄戈 2025-6-5 14:46:49
序言

rustlings 是一个关于rust的练习题的项目.可以帮助大家通过完成一个项目的方式练习rust的语法,我认为对于补充我rust现学现卖过程中的情况很有帮助.
下边是GPT对它的介绍:
Rustlings 是专为那些想要学习 Rust 编程语言的人设计的一个交互式练习集合。无论你是编程新手还是有经验的开发者,Rustlings 都能提供一个友好的环境来探索 Rust 的独特功能。
特点:

  • 互动性: 通过实际编写代码并即时看到结果,你可以更好地理解 Rust 的工作原理。
  • 渐进式难度: 练习按照难易程度排序,从基础到高级逐步引导你深入 Rust。
  • 涵盖广泛: 练习覆盖了 Rust 的主要方面,包括所有权、借用、生命周期、错误处理等。
  • 社区支持: 作为一个活跃的开源项目,Rustlings 拥有一个热情的支持社区,你可以在这里找到帮助或贡献自己的力量。
  • 易于安装: 只需几个简单的命令,就可以在你的机器上设置好 Rustlings,并开始你的学习之旅。
structs2
  1. // structs2.rs
  2. //
  3. // Address all the TODOs to make the tests pass!
  4. //
  5. // Execute `rustlings hint structs2` or use the `hint` watch subcommand for a
  6. // hint.
  7. // I AM NOT DONE
  8. #[derive(Debug)]
  9. struct Order {
  10.     name: String,
  11.     year: u32,
  12.     made_by_phone: bool,
  13.     made_by_mobile: bool,
  14.     made_by_email: bool,
  15.     item_number: u32,
  16.     count: u32,
  17. }
  18. fn create_order_template() -> Order {
  19.     Order {
  20.         name: String::from("Bob"),
  21.         year: 2019,
  22.         made_by_phone: false,
  23.         made_by_mobile: false,
  24.         made_by_email: true,
  25.         item_number: 123,
  26.         count: 0,
  27.     }
  28. }
  29. #[cfg(test)]
  30. mod tests {
  31.     use super::*;
  32.     #[test]
  33.     fn your_order() {
  34.         let order_template = create_order_template();
  35.         // TODO: Create your own order using the update syntax and template above!
  36.         // let your_order =
  37.         let your_order = Order {
  38.             name: String::from("Hacker in Rust"),
  39.             count: 1,
  40.             ..order_template
  41.         };
  42.         assert_eq!(your_order.name, "Hacker in Rust");
  43.         assert_eq!(your_order.year, order_template.year);
  44.         assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
  45.         assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
  46.         assert_eq!(your_order.made_by_email, order_template.made_by_email);
  47.         assert_eq!(your_order.item_number, order_template.item_number);
  48.         assert_eq!(your_order.count, 1);
  49.     }
  50. }
复制代码
这里注意这个,这里有一个结构体更新语法的问题:
  1. let your_order = Order {
  2.             name: String::from("Hacker in Rust"),
  3.             count: 1,
  4.             ..order_template
  5.         };
复制代码
string4

主要是分辨String和&str的区别.
hashmaps3
  1. // hashmaps3.rs
  2. //
  3. // A list of scores (one per line) of a soccer match is given. Each line is of
  4. // the form : "<team_1_name>,<team_2_name>,<team_1_goals>,<team_2_goals>"
  5. // Example: England,France,4,2 (England scored 4 goals, France 2).
  6. //
  7. // You have to build a scores table containing the name of the team, goals the
  8. // team scored, and goals the team conceded. One approach to build the scores
  9. // table is to use a Hashmap. The solution is partially written to use a
  10. // Hashmap, complete it to pass the test.
  11. //
  12. // Make me pass the tests!
  13. //
  14. // Execute `rustlings hint hashmaps3` or use the `hint` watch subcommand for a
  15. // hint.
  16. // I AM NOT DONE
  17. use std::collections::HashMap;
  18. // A structure to store the goal details of a team.
  19. struct Team {
  20.     goals_scored: u8,
  21.     goals_conceded: u8,
  22. }
  23. fn build_scores_table(results: String) -> HashMap<String, Team> {
  24.     // The name of the team is the key and its associated struct is the value.
  25.     let mut scores: HashMap<String, Team> = HashMap::new();
  26.     for r in results.lines() {
  27.         let v: Vec<&str> = r.split(',').collect();
  28.         let team_1_name = v[0].to_string();
  29.         let team_1_score: u8 = v[2].parse().unwrap();
  30.         let team_2_name = v[1].to_string();
  31.         let team_2_score: u8 = v[3].parse().unwrap();
  32.         // TODO: Populate the scores table with details extracted from the
  33.         // current line. Keep in mind that goals scored by team_1
  34.         // will be the number of goals conceded from team_2, and similarly
  35.         // goals scored by team_2 will be the number of goals conceded by
  36.         // team_1.
  37.         let team_1 = scores.entry(team_1_name).or_insert(Team {
  38.             goals_scored: 0,
  39.             goals_conceded: 0,
  40.         });
  41.         team_1.goals_scored += team_1_score;
  42.         team_1.goals_conceded += team_2_score;
  43.         let team_2 = scores.entry(team_2_name).or_insert(Team {
  44.             goals_scored: 0,
  45.             goals_conceded: 0,
  46.         });
  47.         team_2.goals_scored += team_2_score;
  48.         team_2.goals_conceded += team_1_score;
  49.     }
  50.     scores
  51. }
  52. #[cfg(test)]
  53. mod tests {
  54.     use super::*;
  55.     fn get_results() -> String {
  56.         let results = "".to_string()
  57.             + "England,France,4,2\n"
  58.             + "France,Italy,3,1\n"
  59.             + "Poland,Spain,2,0\n"
  60.             + "Germany,England,2,1\n";
  61.         results
  62.     }
  63.     #[test]
  64.     fn build_scores() {
  65.         let scores = build_scores_table(get_results());
  66.         let mut keys: Vec<&String> = scores.keys().collect();
  67.         keys.sort();
  68.         assert_eq!(
  69.             keys,
  70.             vec!["England", "France", "Germany", "Italy", "Poland", "Spain"]
  71.         );
  72.     }
  73.     #[test]
  74.     fn validate_team_score_1() {
  75.         let scores = build_scores_table(get_results());
  76.         let team = scores.get("England").unwrap();
  77.         assert_eq!(team.goals_scored, 5);
  78.         assert_eq!(team.goals_conceded, 4);
  79.     }
  80.     #[test]
  81.     fn validate_team_score_2() {
  82.         let scores = build_scores_table(get_results());
  83.         let team = scores.get("Spain").unwrap();
  84.         assert_eq!(team.goals_scored, 0);
  85.         assert_eq!(team.goals_conceded, 2);
  86.     }
  87. }
复制代码
自动解引用

Deref 解引用 - Rust语言圣经(Rust Course)
所有权借用

#TODO
options2
  1. // options2.rs
  2. //
  3. // Execute `rustlings hint options2` or use the `hint` watch subcommand for a
  4. // hint.
  5. // I AM NOT DONE
  6. #[cfg(test)]
  7. mod tests {
  8.     #[test]
  9.     fn simple_option() {
  10.         let target = "rustlings";
  11.         let optional_target = Some(target);
  12.         // TODO: Make this an if let statement whose value is "Some" type
  13.         if let Some(word) = optional_target {
  14.             assert_eq!(word, target);
  15.         }
  16.     }
  17.     #[test]
  18.     fn layered_option() {
  19.         let range = 10;
  20.         let mut optional_integers: Vec<Option<i8>> = vec![None];
  21.         for i in 1..(range + 1) {
  22.             optional_integers.push(Some(i));
  23.         }
  24.         let mut cursor = range;
  25.         // TODO: make this a while let statement - remember that vector.pop also
  26.         // adds another layer of Option<T>. You can stack `Option<T>`s into
  27.         // while let and if let.
  28.         while let Some(Some(integer)) = optional_integers.pop() {
  29.             assert_eq!(integer, cursor);
  30.             cursor -= 1;
  31.         }
  32.         assert_eq!(cursor, 0);
  33.     }
  34. }
复制代码
这里注意pop本身返回的就是Option,而当初push进去的成员是Some(),因此导致了需要套两层Some来做模式匹配.
options3

这里存在一个所有权的问题:
  1. // options3.rs
  2. //
  3. // Execute `rustlings hint options3` or use the `hint` watch subcommand for a
  4. // hint.
  5. // I AM NOT DONE
  6. struct Point {
  7.     x: i32,
  8.     y: i32,
  9. }
  10. fn main() {
  11.     let y: Option<Point> = Some(Point { x: 100, y: 200 });
  12.     match y {
  13.         Some(ref p) => println!("Co-ordinates are {},{} ", p.x, p.y),
  14.         _ => panic!("no match!"),
  15.     }
  16.     y; // Fix without deleting this line.
  17. }
复制代码
必须加上ref,不然会造成y本身因为被使用因此被move了所有权,那么match结束的时候就会被释放掉,因此只传入它的ref.
errors3

(名词)的传播
返回值 Result 和? - Rust语言圣经(Rust Course)
errors4

PartialEq Trait:

  • PartialEq 是 Rust 标准库中的一个 trait,它允许你定义类型之间的相等性比较。
  • 当你为一个结构体或枚举派生 PartialEq 时,编译器会自动生成一个 == 和 != 操作符的实现,这些操作符将基于结构体或枚举的所有字段进行逐个比较。
  • 如果所有字段都相等,则认为这两个实例是相等的;如果有任何一个字段不相等,则认为它们不相等。
Debug Trait

  • Debug 是另一个标准库中的 trait,它用于格式化调试输出。
  • 当你为一个结构体或枚举派生 Debug 时,编译器会自动生成 fmt:ebug 的实现,这使得你可以使用 {:?} 或 {:#?} 格式说明符来打印该类型的实例。
  • 这对于调试非常有用,因为它可以帮助你查看结构体或枚举实例的内容。
error5
  1. // errors5.rs
  2. //
  3. // This program uses an altered version of the code from errors4.
  4. //
  5. // This exercise uses some concepts that we won't get to until later in the
  6. // course, like `Box` and the `From` trait. It's not important to understand
  7. // them in detail right now, but you can read ahead if you like. For now, think
  8. // of the `Box<dyn ???>` type as an "I want anything that does ???" type, which,
  9. // given Rust's usual standards for runtime safety, should strike you as
  10. // somewhat lenient!
  11. //
  12. // In short, this particular use case for boxes is for when you want to own a
  13. // value and you care only that it is a type which implements a particular
  14. // trait. To do so, The Box is declared as of type Box<dyn Trait> where Trait is
  15. // the trait the compiler looks for on any value used in that context. For this
  16. // exercise, that context is the potential errors which can be returned in a
  17. // Result.
  18. //
  19. // What can we use to describe both errors? In other words, is there a trait
  20. // which both errors implement?
  21. //
  22. // Execute `rustlings hint errors5` or use the `hint` watch subcommand for a
  23. // hint.
  24. // I AM NOT DONE
  25. use std::error;
  26. use std::fmt;
  27. use std::num::ParseIntError;
  28. // TODO: update the return type of `main()` to make this compile.
  29. fn main() -> Result<(), Box<dyn error::Error>> {
  30.     let pretend_user_input = "42";
  31.     let x: i64 = pretend_user_input.parse()?;
  32.     println!("output={:?}", PositiveNonzeroInteger::new(x)?);
  33.     Ok(())
  34. }
  35. // Don't change anything below this line.
  36. #[derive(PartialEq, Debug)]
  37. struct PositiveNonzeroInteger(u64);
  38. #[derive(PartialEq, Debug)]
  39. enum CreationError {
  40.     Negative,
  41.     Zero,
  42. }
  43. impl PositiveNonzeroInteger {
  44.     fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
  45.         match value {
  46.             x if x < 0 => Err(CreationError::Negative),
  47.             x if x == 0 => Err(CreationError::Zero),
  48.             x => Ok(PositiveNonzeroInteger(x as u64)),
  49.         }
  50.     }
  51. }
  52. // This is required so that `CreationError` can implement `error::Error`.
  53. impl fmt::Display for CreationError {
  54.     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  55.         let description = match *self {
  56.             CreationError::Negative => "number is negative",
  57.             CreationError::Zero => "number is zero",
  58.         };
  59.         f.write_str(description)
  60.     }
  61. }
  62. impl error::Error for CreationError {}
复制代码
这里是用dyn error::Error代表的是一个实现了error::Error的struct,而不需要知道这个struct的名字.那么这个对象由编译器在下文中寻找.
意思就是说我不管你这个对象叫什么,只需要实现这个Trait就行了,我需要用到的是你这个struct关于这个Trait的特征.
特征对象 - Rust语言圣经(Rust Course):
特征对象指向实现了 Draw 特征的类型的实例,也就是指向了 Button 或者 SelectBox 的实例,这种映射关系是存储在一张表中,可以在运行时通过特征对象找到具体调用的类型方法。
可以通过 & 引用或者 Box 智能指针的方式来创建特征对象。
那么Box是一种创建特征对象的方式.
对于Box智能指针本身,有解释,我的理解暂时是在上创建一个对象,可以看作包裹的内容是保存在堆上的对象的一个引用.
traits4

这里参考了:捋捋 Rust 中的 impl Trait 和 dyn Trait - 知乎 (zhihu.com)
由于输入的时候不能输入Box包裹,可以直接用impl Trait而不是Box.
但是返回值不能是impl Trait,因为不能返回不同类型,必须加一个包裹.
  1. // traits4.rs
  2. //
  3. // Your task is to replace the '??' sections so the code compiles.
  4. //
  5. // Don't change any line other than the marked one.
  6. //
  7. // Execute `rustlings hint traits4` or use the `hint` watch subcommand for a
  8. // hint.
  9. // I AM NOT DONE
  10. pub trait Licensed {
  11.     fn licensing_info(&self) -> String {
  12.         "some information".to_string()
  13.     }
  14. }
  15. struct SomeSoftware {}
  16. struct OtherSoftware {}
  17. impl Licensed for SomeSoftware {}
  18. impl Licensed for OtherSoftware {}
  19. // YOU MAY ONLY CHANGE THE NEXT LINE
  20. fn compare_license_types(software: impl Licensed, software_two: impl Licensed) -> bool {
  21.     software.licensing_info() == software_two.licensing_info()
  22. }
  23. #[cfg(test)]
  24. mod tests {
  25.     use super::*;
  26.     #[test]
  27.     fn compare_license_information() {
  28.         let some_software = SomeSoftware {};
  29.         let other_software = OtherSoftware {};
  30.         assert!(compare_license_types(some_software, other_software));
  31.     }
  32.     #[test]
  33.     fn compare_license_information_backwards() {
  34.         let some_software = SomeSoftware {};
  35.         let other_software = OtherSoftware {};
  36.         assert!(compare_license_types(other_software, some_software));
  37.     }
  38. }
复制代码
traits5

通过+选定对两个特征的要求.
  1. // traits5.rs
  2. //
  3. // Your task is to replace the '??' sections so the code compiles.
  4. //
  5. // Don't change any line other than the marked one.
  6. //
  7. // Execute `rustlings hint traits5` or use the `hint` watch subcommand for a
  8. // hint.
  9. pub trait SomeTrait {
  10.     fn some_function(&self) -> bool {
  11.         true
  12.     }
  13. }
  14. pub trait OtherTrait {
  15.     fn other_function(&self) -> bool {
  16.         true
  17.     }
  18. }
  19. struct SomeStruct {}
  20. struct OtherStruct {}
  21. impl SomeTrait for SomeStruct {}
  22. impl OtherTrait for SomeStruct {}
  23. impl SomeTrait for OtherStruct {}
  24. impl OtherTrait for OtherStruct {}
  25. // YOU MAY ONLY CHANGE THE NEXT LINE
  26. fn some_func(item: impl SomeTrait + OtherTrait) -> bool {
  27.     item.some_function() && item.other_function()
  28. }
  29. fn main() {
  30.     some_func(SomeStruct {});
  31.     some_func(OtherStruct {});
  32. }
复制代码
quiz3

这里考察的是可以给泛型的每个类型单独写方法.
  1. // quiz3.rs
  2. //
  3. // This quiz tests:
  4. // - Generics
  5. // - Traits
  6. //
  7. // An imaginary magical school has a new report card generation system written
  8. // in Rust! Currently the system only supports creating report cards where the
  9. // student's grade is represented numerically (e.g. 1.0 -> 5.5). However, the
  10. // school also issues alphabetical grades (A+ -> F-) and needs to be able to
  11. // print both types of report card!
  12. //
  13. // Make the necessary code changes in the struct ReportCard and the impl block
  14. // to support alphabetical report cards. Change the Grade in the second test to
  15. // "A+" to show that your changes allow alphabetical grades.
  16. //
  17. // Execute `rustlings hint quiz3` or use the `hint` watch subcommand for a hint.
  18. pub struct ReportCard<T> {
  19.     pub grade: T,
  20.     pub student_name: String,
  21.     pub student_age: u8,
  22. }
  23. impl ReportCard<f32> {
  24.     pub fn print(&self) -> String {
  25.         format!("{} ({}) - achieved a grade of {}",
  26.             &self.student_name, &self.student_age, &self.grade)
  27.     }
  28. }
  29. impl ReportCard<&str> {
  30.     pub fn print(&self) -> String {
  31.         format!("{} ({}) - achieved a grade of {}",
  32.             &self.student_name, &self.student_age, &self.grade)
  33.     }
  34. }
  35. #[cfg(test)]
  36. mod tests {
  37.     use super::*;
  38.     #[test]
  39.     fn generate_numeric_report_card() {
  40.         let report_card = ReportCard {
  41.             grade: 2.1,
  42.             student_name: "Tom Wriggle".to_string(),
  43.             student_age: 12,
  44.         };
  45.         assert_eq!(
  46.             report_card.print(),
  47.             "Tom Wriggle (12) - achieved a grade of 2.1"
  48.         );
  49.     }
  50.     #[test]
  51.     fn generate_alphabetic_report_card() {
  52.         // TODO: Make sure to change the grade here after you finish the exercise.
  53.         let report_card = ReportCard {
  54.             grade: "A+",
  55.             student_name: "Gary Plotter".to_string(),
  56.             student_age: 11,
  57.         };
  58.         assert_eq!(
  59.             report_card.print(),
  60.             "Gary Plotter (11) - achieved a grade of A+"
  61.         );
  62.     }
  63. }
复制代码
lifetimes1

认识生命周期 - Rust语言圣经(Rust Course)
  1. // lifetimes1.rs
  2. //
  3. // The Rust compiler needs to know how to check whether supplied references are
  4. // valid, so that it can let the programmer know if a reference is at risk of
  5. // going out of scope before it is used. Remember, references are borrows and do
  6. // not own their own data. What if their owner goes out of scope?
  7. //
  8. // Execute `rustlings hint lifetimes1` or use the `hint` watch subcommand for a
  9. // hint.
  10. // I AM NOT DONE
  11. fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
  12.     if x.len() > y.len() {
  13.         x
  14.     } else {
  15.         y
  16.     }
  17. }
  18. fn main() {
  19.     let string1 = String::from("abcd");
  20.     let string2 = "xyz";
  21.     let result = longest(string1.as_str(), string2);
  22.     println!("The longest string is '{}'", result);
  23. }
复制代码
tests4

这个报错过不了啊!!!!
  1. // tests4.rs
  2. //
  3. // Make sure that we're testing for the correct conditions!
  4. //
  5. // Execute `rustlings hint tests4` or use the `hint` watch subcommand for a
  6. // hint.
  7. // I AM NOT DONE
  8. struct Rectangle {
  9.     width: i32,
  10.     height: i32
  11. }
  12. impl Rectangle {
  13.     // Only change the test functions themselves
  14.     pub fn new(width: i32, height: i32) -> Self {
  15.         if width <= 0 || height <= 0 {
  16.             panic!("Rectangle width and height cannot be negative!")
  17.         }
  18.         Rectangle {width, height}
  19.     }
  20. }
  21. #[cfg(test)]
  22. mod tests {
  23.     use super::*;
  24.     #[test]
  25.     fn correct_width_and_height() {
  26.         // This test should check if the rectangle is the size that we pass into its constructor
  27.         let rect = Rectangle::new(10, 20);
  28.         assert_eq!(rect.width, 10); // check width
  29.         assert_eq!(rect.height, 20); // check height
  30.     }
  31.     #[test]
  32.     fn negative_width() {
  33.         // This test should check if program panics when we try to create rectangle with negative width
  34.         // let _rect = Rectangle::new(-10, 10);
  35.     }
  36.     #[test]
  37.     fn negative_height() {
  38.         // This test should check if program panics when we try to create rectangle with negative height
  39.         // let _rect = Rectangle::new(10, -10);
  40.     }
  41. }
复制代码
iterators4

区间表达式 - Rust 参考手册 中文版 (rustwiki.org)
  1. // iterators1.rs
  2. //
  3. // When performing operations on elements within a collection, iterators are
  4. // essential. This module helps you get familiar with the structure of using an
  5. // iterator and how to go through elements within an iterable collection.
  6. //
  7. // Make me compile by filling in the `???`s
  8. //
  9. // Execute `rustlings hint iterators1` or use the `hint` watch subcommand for a
  10. // hint.
  11. // I AM NOT DONE
  12. fn main() {
  13.     let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"];
  14.     let mut my_iterable_fav_fruits = my_fav_fruits.iter();   // TODO: Step 1
  15.     assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana"));
  16.     assert_eq!(my_iterable_fav_fruits.next(), Some(&"custard apple"));     // TODO: Step 2
  17.     assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado"));
  18.     assert_eq!(my_iterable_fav_fruits.next(), Some(&"peach"));     // TODO: Step 3
  19.     assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));
  20.     assert_eq!(my_iterable_fav_fruits.next(), None);     // TODO: Step 4
  21. }
复制代码
iterator5

这里存在一个认知问题,就是还是存在对:

  • 引用和自动解引用和*
  • for的语法糖
  • 借用
不熟悉
  1. // iterators3.rs
  2. //
  3. // This is a bigger exercise than most of the others! You can do it! Here is
  4. // your mission, should you choose to accept it:
  5. // 1. Complete the divide function to get the first four tests to pass.
  6. // 2. Get the remaining tests to pass by completing the result_with_list and
  7. //    list_of_results functions.
  8. //
  9. // Execute `rustlings hint iterators3` or use the `hint` watch subcommand for a
  10. // hint.
  11. // I AM NOT DONE
  12. #[derive(Debug, PartialEq, Eq)]
  13. pub enum DivisionError {
  14.     NotDivisible(NotDivisibleError),
  15.     DivideByZero,
  16. }
  17. #[derive(Debug, PartialEq, Eq)]
  18. pub struct NotDivisibleError {
  19.     dividend: i32,
  20.     divisor: i32,
  21. }
  22. // Calculate `a` divided by `b` if `a` is evenly divisible by `b`.
  23. // Otherwise, return a suitable error.
  24. pub fn divide(a: i32, b: i32) -> Result<i32, DivisionError> {
  25.     if b == 0{
  26.         return Err(DivisionError::DivideByZero);
  27.     }
  28.     let r = a/b;
  29.     if r*b==a{
  30.         Ok(r)
  31.     }else{
  32.         Err(DivisionError::NotDivisible(NotDivisibleError{dividend:a,divisor:b}))
  33.     }
  34. }
  35. // Complete the function and return a value of the correct type so the test
  36. // passes.
  37. // Desired output: Ok([1, 11, 1426, 3])
  38. fn result_with_list() -> Result<Vec<i32>,DivisionError> {
  39.     let numbers = vec![27, 297, 38502, 81];
  40.     let division_results = numbers.into_iter().map(|n| divide(n, 27));
  41.     division_results.collect::<Result<Vec<i32>, DivisionError>>()
  42. }
  43. // Complete the function and return a value of the correct type so the test
  44. // passes.
  45. // Desired output: [Ok(1), Ok(11), Ok(1426), Ok(3)]
  46. fn list_of_results() -> Vec<Result<i32, DivisionError>> {
  47.     let numbers = vec![27, 297, 38502, 81];
  48.     let division_results = numbers.into_iter().map(|n| divide(n, 27));
  49.     division_results.collect::<Vec<Result<i32, DivisionError>>>()
  50. }
  51. #[cfg(test)]
  52. mod tests {
  53.     use super::*;
  54.     #[test]
  55.     fn test_success() {
  56.         assert_eq!(divide(81, 9), Ok(9));
  57.     }
  58.     #[test]
  59.     fn test_not_divisible() {
  60.         assert_eq!(
  61.             divide(81, 6),
  62.             Err(DivisionError::NotDivisible(NotDivisibleError {
  63.                 dividend: 81,
  64.                 divisor: 6
  65.             }))
  66.         );
  67.     }
  68.     #[test]
  69.     fn test_divide_by_0() {
  70.         assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero));
  71.     }
  72.     #[test]
  73.     fn test_divide_0_by_something() {
  74.         assert_eq!(divide(0, 81), Ok(0));
  75.     }
  76.     #[test]
  77.     fn test_result_with_list() {
  78.         assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])");
  79.     }
  80.     #[test]
  81.     fn test_list_of_results() {
  82.         assert_eq!(
  83.             format!("{:?}", list_of_results()),
  84.             "[Ok(1), Ok(11), Ok(1426), Ok(3)]"
  85.         );
  86.     }
  87. }
复制代码
cow1

这里如果像我一样很难理解高级语言,那么我们可以去看它的实现.
这里Cow实现了两个Trait,而且是在泛型的情况下专门的类型适配了专门的特性.
这里这两个from就引起了我的思考:

  • &[T]和[T]之间有什么引用和引用的目标之间的自动转换.

    • 尤其是println!输出多层引用的时候误导了我.
    • Deref 解引用使得这种误导更加严重,Rust中的 实现了Deref 的类型.

  • Cow的from是根据类型实现的泛型.
根据这一节所学,可以看到本来就是在讨论Cow在面对引用和引用的目标时候有不同的表现,因此应该不是自动进行了解引用:

  • Cow对&[T]的from实现

    • Creates a Borrowed variant of Cow from a slice. 可以看到,是创建了一个Borrowed.

  • Cow对Vec的实现

    • Creates an Owned variant of Cow from an owned instance of Vec. 可以看到是创建了一个Owned.

这里看源码看了半天找不到的原因是没有弄明白&[T],[T],Vec,vec!的区别.

  • 首先[T]是数组Vec是可变数组,是不同的.
  • &[T]是一个数组的引用.
  • vec!是一个宏,返回的是Vec.
这里必须提到,Cow没有实现对于[T]的from,所以其中使用的是vec!返回的Vec.
例子中,一会使用&[T]一会使用Vec给了我非常大的误导
这里还有一个遗漏的点,数组切片.
let mut input = Cow::from(&slice[..]); 这一句用的就是数组切片.
  1. // iterators4.rs
  2. //
  3. // Execute `rustlings hint iterators4` or use the `hint` watch subcommand for a
  4. // hint.
  5. // I AM NOT DONE
  6. pub fn factorial(num: u64) -> u64 {
  7.     // Complete this function to return the factorial of num
  8.     // Do not use:
  9.     // - return
  10.     // Try not to use:
  11.     // - imperative style loops (for, while)
  12.     // - additional variables
  13.     // For an extra challenge, don't use:
  14.     // - recursion
  15.     // Execute `rustlings hint iterators4` for hints.
  16.     (1..=num).product()
  17. }
  18. #[cfg(test)]
  19. mod tests {
  20.     use super::*;
  21.     #[test]
  22.     fn factorial_of_0() {
  23.         assert_eq!(1, factorial(0));
  24.     }
  25.     #[test]
  26.     fn factorial_of_1() {
  27.         assert_eq!(1, factorial(1));
  28.     }
  29.     #[test]
  30.     fn factorial_of_2() {
  31.         assert_eq!(2, factorial(2));
  32.     }
  33.     #[test]
  34.     fn factorial_of_4() {
  35.         assert_eq!(24, factorial(4));
  36.     }
  37. }
复制代码
threads1

如果大家学过其它语言的多线程,可能就知道不同语言对于线程的实现可能大相径庭:

  • 由于操作系统提供了创建线程的 API,因此部分语言会直接调用该 API 来创建线程,因此最终程序内的线程数和该程序占用的操作系统线程数相等,一般称之为1:1 线程模型,例如 Rust。
  • 还有些语言在内部实现了自己的线程模型(绿色线程、协程),程序内部的 M 个线程最后会以某种映射方式使用 N 个操作系统线程去运行,因此称之为M:N 线程模型,其中 M 和 N 并没有特定的彼此限制关系。一个典型的代表就是 Go 语言。
  • 还有些语言使用了 Actor 模型,基于消息传递进行并发,例如 Erlang 语言。
总之,每一种模型都有其优缺点及选择上的权衡,而 Rust 在设计时考虑的权衡就是运行时(Runtime)。出于 Rust 的系统级使用场景,且要保证调用 C 时的极致性能,它最终选择了尽量小的运行时实现。
有时候只看一本书是不够的,还需要多看几本书.
  1. // iterators5.rs
  2. //
  3. // Let's define a simple model to track Rustlings exercise progress. Progress
  4. // will be modelled using a hash map. The name of the exercise is the key and
  5. // the progress is the value. Two counting functions were created to count the
  6. // number of exercises with a given progress. Recreate this counting
  7. // functionality using iterators. Try not to use imperative loops (for, while).
  8. // Only the two iterator methods (count_iterator and count_collection_iterator)
  9. // need to be modified.
  10. //
  11. // Execute `rustlings hint iterators5` or use the `hint` watch subcommand for a
  12. // hint.
  13. // I AM NOT DONE
  14. use std::collections::HashMap;
  15. #[derive(Clone, Copy, PartialEq, Eq)]
  16. enum Progress {
  17.     None,
  18.     Some,
  19.     Complete,
  20. }
  21. fn count_for(map: &HashMap<String, Progress>, value: Progress) -> usize {
  22.     let mut count = 0;
  23.     for val in map.values() {
  24.         if val == &value {
  25.             count += 1;
  26.         }
  27.     }
  28.     count
  29. }
  30. fn count_iterator(map: &HashMap<String, Progress>, value: Progress) -> usize {
  31.     // map is a hashmap with String keys and Progress values.
  32.     // map = { "variables1": Complete, "from_str": None, ... }
  33.     map.values().filter(|v| *v==&value).count()
  34. }
  35. fn count_collection_for(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
  36.     let mut count = 0;
  37.     for map in collection {
  38.         for val in map.values() {
  39.             if val == &value {
  40.                 count += 1;
  41.             }
  42.         }
  43.     }
  44.     count
  45. }
  46. fn count_collection_iterator(collection: &[HashMap<String, Progress>], value: Progress) -> usize {
  47.     // collection is a slice of hashmaps.
  48.     // collection = [{ "variables1": Complete, "from_str": None, ... },
  49.     //     { "variables2": Complete, ... }, ... ]
  50.     collection.into_iter().map(|c| count_iterator(c,value)).sum()
  51. }
  52. #[cfg(test)]
  53. mod tests {
  54.     use super::*;
  55.     #[test]
  56.     fn count_complete() {
  57.         let map = get_map();
  58.         assert_eq!(3, count_iterator(&map, Progress::Complete));
  59.     }
  60.     #[test]
  61.     fn count_some() {
  62.         let map = get_map();
  63.         assert_eq!(1, count_iterator(&map, Progress::Some));
  64.     }
  65.     #[test]
  66.     fn count_none() {
  67.         let map = get_map();
  68.         assert_eq!(2, count_iterator(&map, Progress::None));
  69.     }
  70.     #[test]
  71.     fn count_complete_equals_for() {
  72.         let map = get_map();
  73.         let progress_states = vec![Progress::Complete, Progress::Some, Progress::None];
  74.         for progress_state in progress_states {
  75.             assert_eq!(
  76.                 count_for(&map, progress_state),
  77.                 count_iterator(&map, progress_state)
  78.             );
  79.         }
  80.     }
  81.     #[test]
  82.     fn count_collection_complete() {
  83.         let collection = get_vec_map();
  84.         assert_eq!(
  85.             6,
  86.             count_collection_iterator(&collection, Progress::Complete)
  87.         );
  88.     }
  89.     #[test]
  90.     fn count_collection_some() {
  91.         let collection = get_vec_map();
  92.         assert_eq!(1, count_collection_iterator(&collection, Progress::Some));
  93.     }
  94.     #[test]
  95.     fn count_collection_none() {
  96.         let collection = get_vec_map();
  97.         assert_eq!(4, count_collection_iterator(&collection, Progress::None));
  98.     }
  99.     #[test]
  100.     fn count_collection_equals_for() {
  101.         let progress_states = vec![Progress::Complete, Progress::Some, Progress::None];
  102.         let collection = get_vec_map();
  103.         for progress_state in progress_states {
  104.             assert_eq!(
  105.                 count_collection_for(&collection, progress_state),
  106.                 count_collection_iterator(&collection, progress_state)
  107.             );
  108.         }
  109.     }
  110.     fn get_map() -> HashMap<String, Progress> {
  111.         use Progress::*;
  112.         let mut map = HashMap::new();
  113.         map.insert(String::from("variables1"), Complete);
  114.         map.insert(String::from("functions1"), Complete);
  115.         map.insert(String::from("hashmap1"), Complete);
  116.         map.insert(String::from("arc1"), Some);
  117.         map.insert(String::from("as_ref_mut"), None);
  118.         map.insert(String::from("from_str"), None);
  119.         map
  120.     }
  121.     fn get_vec_map() -> Vec<HashMap<String, Progress>> {
  122.         use Progress::*;
  123.         let map = get_map();
  124.         let mut other = HashMap::new();
  125.         other.insert(String::from("variables2"), Complete);
  126.         other.insert(String::from("functions2"), Complete);
  127.         other.insert(String::from("if1"), Complete);
  128.         other.insert(String::from("from_into"), None);
  129.         other.insert(String::from("try_from_into"), None);
  130.         vec![map, other]
  131.     }
  132. }
复制代码
thread2

告诉我们一个道理join只是检测线程有没有运行,不一定是你join的时候它才运行的.
另外就是用好互斥锁Mutex和RefCell:

  • RefCell是一个纯在单线程环境中的可变,可以配合Rc完成单线程中共享变量的安全,并且可以修改其中成员的值.
  • Mutex是我们熟悉的互斥锁,支持多线程,和Arc可以配合好
  1. // cow1.rs
  2. //
  3. // This exercise explores the Cow, or Clone-On-Write type. Cow is a
  4. // clone-on-write smart pointer. It can enclose and provide immutable access to
  5. // borrowed data, and clone the data lazily when mutation or ownership is
  6. // required. The type is designed to work with general borrowed data via the
  7. // Borrow trait.
  8. //
  9. // This exercise is meant to show you what to expect when passing data to Cow.
  10. // Fix the unit tests by checking for Cow::Owned(_) and Cow::Borrowed(_) at the
  11. // TODO markers.
  12. //
  13. // Execute `rustlings hint cow1` or use the `hint` watch subcommand for a hint.
  14. // I AM NOT DONE
  15. use std::borrow::Cow;
  16. fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> {
  17.     for i in 0..input.len() {
  18.         let v = input[i];
  19.         if v < 0 {
  20.             // Clones into a vector if not already owned.
  21.             input.to_mut()[i] = -v;
  22.         }
  23.     }
  24.     input
  25. }
  26. #[cfg(test)]
  27. mod tests {
  28.     use super::*;
  29.     #[test]
  30.     fn reference_mutation() -> Result<(), &'static str> {
  31.         // Clone occurs because `input` needs to be mutated.
  32.         let slice = [-1, 0, 1];
  33.         let mut input = Cow::from(&slice[..]);
  34.         match abs_all(&mut input) {
  35.             Cow::Owned(_) => Ok(()),
  36.             _ => Err("Expected owned value"),
  37.         }
  38.     }
  39.     #[test]
  40.     fn reference_no_mutation() -> Result<(), &'static str> {
  41.         // No clone occurs because `input` doesn't need to be mutated.
  42.         let slice = [0, 1, 2];
  43.         let mut input = Cow::from(&slice[..]);
  44.         match abs_all(&mut input) {
  45.             Cow::Borrowed(_) => Ok(()),
  46.             _ => Err("Expected owned value"),
  47.         }
  48.     }
  49.     #[test]
  50.     fn owned_no_mutation() -> Result<(), &'static str> {
  51.         // We can also pass `slice` without `&` so Cow owns it directly. In this
  52.         // case no mutation occurs and thus also no clone, but the result is
  53.         // still owned because it was never borrowed or mutated.
  54.         let slice = vec![0, 1, 2];
  55.         let mut input = Cow::from(slice);
  56.         match abs_all(&mut input) {
  57.             Cow::Owned(_) => Ok(()),
  58.             _ => Err("Expected owned value"),
  59.         }
  60.     }
  61.     #[test]
  62.     fn owned_mutation() -> Result<(), &'static str> {
  63.         // Of course this is also the case if a mutation does occur. In this
  64.         // case the call to `to_mut()` returns a reference to the same data as
  65.         // before.
  66.         let slice = vec![-1, 0, 1];
  67.         let mut input = Cow::from(slice);
  68.         match abs_all(&mut input) {
  69.             Cow::Owned(_) => Ok(()),
  70.             _ => Err("Expected owned value"),
  71.         }
  72.     }
  73. }
复制代码
log
  1. // threads1.rs
  2. //
  3. // This program spawns multiple threads that each run for at least 250ms, and
  4. // each thread returns how much time they took to complete. The program should
  5. // wait until all the spawned threads have finished and should collect their
  6. // return values into a vector.
  7. //
  8. // Execute `rustlings hint threads1` or use the `hint` watch subcommand for a
  9. // hint.
  10. use std::thread;
  11. use std::time::{Duration, Instant};
  12. fn main() {
  13.     let mut handles = vec![];
  14.     for i in 0..10 {
  15.         handles.push(thread::spawn(move || {
  16.             let start = Instant::now();
  17.             thread::sleep(Duration::from_millis(250));
  18.             println!("thread {} is complete", i);
  19.             start.elapsed().as_millis()
  20.         }));
  21.     }
  22.     let mut results: Vec<u128> = vec![];
  23.     for handle in handles {
  24.         // TODO: a struct is returned from thread::spawn, can you use it?
  25.         results.push({
  26.             match handle.join(){
  27.                 Ok(t) => t,
  28.                 Err(_) => panic!("Some thing wrong!!!")
  29.             }
  30.         })
  31.     }
  32.     if results.len() != 10 {
  33.         panic!("Oh no! All the spawned threads did not finish!");
  34.     }
  35.     println!();
  36.     for (i, result) in results.into_iter().enumerate() {
  37.         println!("thread {} took {}ms", i, result);
  38.     }
  39. }
复制代码
from_str

好的逻辑是计划出来的是想出来的,不是混出来的,不是尝试出来的,如果这也要以做出来为标准,那么你学了什么呢?
  1. // threads2.rs
  2. //
  3. // Building on the last exercise, we want all of the threads to complete their
  4. // work but this time the spawned threads need to be in charge of updating a
  5. // shared value: JobStatus.jobs_completed
  6. //
  7. // Execute `rustlings hint threads2` or use the `hint` watch subcommand for a
  8. // hint.
  9. // I AM NOT DONE
  10. use std::sync::{Arc,Mutex};
  11. use std::thread;
  12. use std::time::Duration;
  13. struct JobStatus {
  14.     jobs_completed: u32,
  15. }
  16. fn main() {
  17.     let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
  18.     let mut handles = vec![];
  19.     for _ in 0..10 {
  20.         let status_shared = Arc::clone(&status);
  21.         let handle = thread::spawn(move || {
  22.             thread::sleep(Duration::from_millis(250));
  23.             // TODO: You must take an action before you update a shared value
  24.             let mut status_shared  = match status_shared.lock()
  25.             {
  26.                 Ok(status) => status,
  27.                 Err(_) => panic!("Error")  
  28.             };
  29.             status_shared.jobs_completed += 1;
  30.         });
  31.         handles.push(handle);
  32.     }
  33.     for handle in handles {
  34.         handle.join().unwrap();
  35.         // TODO: Print the value of the JobStatus.jobs_completed. Did you notice
  36.         // anything interesting in the output? Do you have to 'join' on all the
  37.         // handles?
  38.         let status = status.lock().unwrap();
  39.         println!("jobs completed {}", status.jobs_completed);
  40.     }
  41. }
复制代码
algorithm4


使用 value.cmp 可以防止 T 不支持>, Self {        TreeNode {            value,            left: None,            right: None,        }    }}impl BinarySearchTreewhere    T: Ord,{    fn new() -> Self {        BinarySearchTree { root: None }    }    // Insert a value into the BST    fn insert(&mut self, value: T) {        //TODO        let mut current = &mut self.root;        while let Some(ref mut node) = current {            if value < node.value {                current = &mut node.left;            } else if value > node.value {                current = &mut node.right;            } else {                return;            }        }        *current = Some(Box::new(TreeNode::new(value)));    }    // Search for a value in the BST    fn search(&self, value: T) -> bool {        let mut current = &self.root;        while let Some(node) = current {            match value.cmp(&node.value) {                Ordering:ess => current = &node.left,                Ordering::Greater => current = &node.right,                Ordering::Equal => return true,            }        }        false    }}impl TreeNodewhere    T: Ord,{    // Insert a node into the tree    fn insert(&mut self, value: T) {        if value  panic!("There is all ready a node left"),                None => self.left = Some(Box::new(TreeNode::::new(value))),            };        }else{            match self.right{                Some(_) => panic!("There is all ready a node right"),                None => self.right = Some(Box::new(TreeNode::::new(value))),            }        }    }    fn is_full(self) -> bool{        (!self.left.is_none()) && (!self.right.is_none())    }}#[cfg(test)]mod tests {    use super::*;    #[test]    fn test_insert_and_search() {        let mut bst = BinarySearchTree::new();                assert_eq!(bst.search(1), false);                bst.insert(5);        bst.insert(3);        bst.insert(7);        bst.insert(2);        bst.insert(4);                assert_eq!(bst.search(5), true);        assert_eq!(bst.search(3), true);        assert_eq!(bst.search(7), true);        assert_eq!(bst.search(2), true);        assert_eq!(bst.search(4), true);                assert_eq!(bst.search(1), false);        assert_eq!(bst.search(6), false);    }    #[test]    fn test_insert_duplicate() {        let mut bst = BinarySearchTree::new();                bst.insert(1);        bst.insert(1);                assert_eq!(bst.search(1), true);                match bst.root {            Some(ref node) => {                assert!(node.left.is_none());                assert!(node.right.is_none());            },            None => panic!("Root should not be None after insertion"),        }    }}    [/code]algorithm6

无比丑陋的DFS.
#TODO 写点好看的吧.
  1. Output:
  2. ====================
  3. jobs completed 6
  4. jobs completed 6
  5. jobs completed 6
  6. jobs completed 7
  7. jobs completed 7
  8. jobs completed 7
  9. jobs completed 10
  10. jobs completed 10
  11. jobs completed 10
  12. jobs completed 10
  13. ====================
复制代码
不写递归的后果:
GPT写的,多么的聪明
  1. // from_str.rs
  2. //
  3. // This is similar to from_into.rs, but this time we'll implement `FromStr` and
  4. // return errors instead of falling back to a default value. Additionally, upon
  5. // implementing FromStr, you can use the `parse` method on strings to generate
  6. // an object of the implementor type. You can read more about it at
  7. // https://doc.rust-lang.org/std/str/trait.FromStr.html
  8. //
  9. // Execute `rustlings hint from_str` or use the `hint` watch subcommand for a
  10. // hint.
  11. use std::num::ParseIntError;
  12. use std::str::FromStr;
  13. #[derive(Debug, PartialEq)]
  14. struct Person {
  15.     name: String,
  16.     age: usize,
  17. }
  18. // We will use this error type for the `FromStr` implementation.
  19. #[derive(Debug, PartialEq)]
  20. enum ParsePersonError {
  21.     // Empty input string
  22.     Empty,
  23.     // Incorrect number of fields
  24.     BadLen,
  25.     // Empty name field
  26.     NoName,
  27.     // Wrapped error from parse::<usize>()
  28.     ParseInt(ParseIntError),
  29. }
  30. // I AM NOT DONE
  31. // Steps:
  32. // 1. If the length of the provided string is 0, an error should be returned
  33. // 2. Split the given string on the commas present in it
  34. // 3. Only 2 elements should be returned from the split, otherwise return an
  35. //    error
  36. // 4. Extract the first element from the split operation and use it as the name
  37. // 5. Extract the other element from the split operation and parse it into a
  38. //    `usize` as the age with something like `"4".parse::<usize>()`
  39. // 6. If while extracting the name and the age something goes wrong, an error
  40. //    should be returned
  41. // If everything goes well, then return a Result of a Person object
  42. //
  43. // As an aside: `Box<dyn Error>` implements `From<&'_ str>`. This means that if
  44. // you want to return a string error message, you can do so via just using
  45. // return `Err("my error message".into())`.
  46. impl FromStr for Person {
  47.     type Err = ParsePersonError;
  48.     fn from_str(s: &str) -> Result<Person, Self::Err> {
  49.         if s.is_empty() {
  50.             return Err(ParsePersonError::Empty);
  51.         }
  52.         let v:Vec<_> = s.split(",").collect();
  53.         if v.len() != 2{
  54.             return Err(ParsePersonError::BadLen);
  55.         }
  56.         let name = {
  57.             if v[0].is_empty(){
  58.                 return Err(ParsePersonError::NoName);
  59.             }
  60.             v[0].to_string()
  61.         };
  62.         let age = match v[1].parse::<usize>(){
  63.             Ok(age) => age,
  64.             Err(err) => return Err(ParsePersonError::ParseInt(err))
  65.         };
  66.         Ok(Person{
  67.             name: name,
  68.             age: age,
  69.         })
  70.     }
  71. }
  72. fn main() {
  73.     let p = "Mark,20".parse::<Person>().unwrap();
  74.     println!("{:?}", p);
  75. }
  76. #[cfg(test)]
  77. mod tests {
  78.     use super::*;
  79.     #[test]
  80.     fn empty_input() {
  81.         assert_eq!("".parse::<Person>(), Err(ParsePersonError::Empty));
  82.     }
  83.     #[test]
  84.     fn good_input() {
  85.         let p = "John,32".parse::<Person>();
  86.         assert!(p.is_ok());
  87.         let p = p.unwrap();
  88.         assert_eq!(p.name, "John");
  89.         assert_eq!(p.age, 32);
  90.     }
  91.     #[test]
  92.     fn missing_age() {
  93.         assert!(matches!(
  94.             "John,".parse::<Person>(),
  95.             Err(ParsePersonError::ParseInt(_))
  96.         ));
  97.     }
  98.     #[test]
  99.     fn invalid_age() {
  100.         assert!(matches!(
  101.             "John,twenty".parse::<Person>(),
  102.             Err(ParsePersonError::ParseInt(_))
  103.         ));
  104.     }
  105.     #[test]
  106.     fn missing_comma_and_age() {
  107.         assert_eq!("John".parse::<Person>(), Err(ParsePersonError::BadLen));
  108.     }
  109.     #[test]
  110.     fn missing_name() {
  111.         assert_eq!(",1".parse::<Person>(), Err(ParsePersonError::NoName));
  112.     }
  113.     #[test]
  114.     fn missing_name_and_age() {
  115.         assert!(matches!(
  116.             ",".parse::<Person>(),
  117.             Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))
  118.         ));
  119.     }
  120.     #[test]
  121.     fn missing_name_and_invalid_age() {
  122.         assert!(matches!(
  123.             ",one".parse::<Person>(),
  124.             Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))
  125.         ));
  126.     }
  127.     #[test]
  128.     fn trailing_comma() {
  129.         assert_eq!("John,32,".parse::<Person>(), Err(ParsePersonError::BadLen));
  130.     }
  131.     #[test]
  132.     fn trailing_comma_and_some_string() {
  133.         assert_eq!(
  134.             "John,32,man".parse::<Person>(),
  135.             Err(ParsePersonError::BadLen)
  136.         );
  137.     }
  138. }
复制代码
algorithm8

这里出现一个借用性问题: #TODO
  1. //! This is the build script for both tests7 and tests8.
  2. //!
  3. //! You should modify this file to make both exercises pass.
  4. fn main() {
  5.     // In tests7, we should set up an environment variable
  6.     // called `TEST_FOO`. Print in the standard output to let
  7.     // Cargo do it.
  8.     let timestamp = std::time::SystemTime::now()
  9.         .duration_since(std::time::UNIX_EPOCH)
  10.         .unwrap()
  11.         .as_secs(); // What's the use of this timestamp here?
  12.     let your_command = format!(
  13.         "rustc-env=TEST_FOO={}",
  14.         timestamp.to_string()
  15.     );
  16.     println!("cargo:{}", your_command);
  17.     // In tests8, we should enable "pass" feature to make the
  18.     // testcase return early. Fill in the command to tell
  19.     // Cargo about that.
  20.     // let your_command = "Your command here, please checkout exercises/tests/build.rs";
  21.     // println!("cargo:{}", your_command);
  22. }
复制代码
不能被改成:
`
  1. // tests9.rs
  2. //
  3. // Rust is highly capable of sharing FFI interfaces with C/C++ and other statically compiled
  4. // languages, and it can even link within the code itself! It makes it through the extern
  5. // block, just like the code below.
  6. //
  7. // The short string after the `extern` keyword indicates which ABI the externally imported
  8. // function would follow. In this exercise, "Rust" is used, while other variants exists like
  9. // "C" for standard C ABI, "stdcall" for the Windows ABI.
  10. //
  11. // The externally imported functions are declared in the extern blocks, with a semicolon to
  12. // mark the end of signature instead of curly braces. Some attributes can be applied to those
  13. // function declarations to modify the linking behavior, such as #[link_name = ".."] to
  14. // modify the actual symbol names.
  15. //
  16. // If you want to export your symbol to the linking environment, the `extern` keyword can
  17. // also be marked before a function definition with the same ABI string note. The default ABI
  18. // for Rust functions is literally "Rust", so if you want to link against pure Rust functions,
  19. // the whole extern term can be omitted.
  20. //
  21. // Rust mangles symbols by default, just like C++ does. To suppress this behavior and make
  22. // those functions addressable by name, the attribute #[no_mangle] can be applied.
  23. //
  24. // In this exercise, your task is to make the testcase able to call the `my_demo_function` in
  25. // module Foo. the `my_demo_function_alias` is an alias for `my_demo_function`, so the two
  26. // line of code in the testcase should call the same function.
  27. //
  28. // You should NOT modify any existing code except for adding two lines of attributes.
  29. // I AM NOT DONE
  30. extern "Rust" {
  31.     #[no_mangle]
  32.     fn my_demo_function(a: u32) -> u32;
  33.     #[no_mangle]
  34.     #[link_name = "my_demo_function"]
  35.     fn my_demo_function_alias(a: u32) -> u32;
  36. }
  37. mod Foo {
  38.     // No `extern` equals `extern "Rust"`.
  39.     #[no_mangle]
  40.     fn my_demo_function(a: u32) -> u32 {
  41.         a
  42.     }
  43. }
  44. #[cfg(test)]
  45. mod tests {
  46.     use super::*;
  47.     #[test]
  48.     fn test_success() {
  49.         // The externally imported functions are UNSAFE by default
  50.         // because of untrusted source of other languages. You may
  51.         // wrap them in safe Rust APIs to ease the burden of callers.
  52.         //
  53.         // SAFETY: We know those functions are aliases of a safe
  54.         // Rust function.
  55.         unsafe {
  56.             my_demo_function(123);
  57.             my_demo_function_alias(456);
  58.         }
  59.     }
  60. }
复制代码
  1. /*        queue        This question requires you to use queues to implement the functionality of the stac*/// I AM NOT DONE#[derive(Debug)]pub struct Queue {    elements: Vec,}impl Queue {    pub fn new() -> Queue {        Queue {            elements: Vec::new(),        }    }    pub fn enqueue(&mut self, value: T) {        self.elements.push(value)    }    pub fn dequeue(&mut self) -> Result {        if !self.elements.is_empty() {            Ok(self.elements.remove(0usize))        } else {            Err("Queue is empty")        }    }    pub fn peek(&self) -> Result {        match self.elements.first() {            Some(value) => Ok(value),            None => Err("Queue is empty"),        }    }    pub fn size(&self) -> usize {        self.elements.len()    }    pub fn is_empty(&self) -> bool {        self.elements.is_empty()    }}impl Default for Queue {    fn default() -> Queue {        Queue {            elements: Vec::new(),        }    }}enum SelectedQueue{    Q1,    Q2,}pub struct myStack{        //TODO    flag: SelectedQueue,        q1:Queue,        q2:Queue}impl myStack {    pub fn new() -> Self {        Self {                        //TODO            flag: SelectedQueue::Q1,                        q1:Queue::::new(),                        q2:Queue::::new()        }    }    pub fn push(&mut self, elem: T) {        //TODO        let q = match self.flag{            SelectedQueue::Q1 => &mut self.q1,            SelectedQueue::Q2 => &mut self.q2,        };        q.enqueue(elem);    }    pub fn pop(& mut self) -> Result {        //TODO        let (q1,q2) = match self.flag{            SelectedQueue::Q1 => (&mut self.q1,&mut self.q2),            SelectedQueue::Q2 => (&mut self.q2,&mut self.q1),        };        if q1.is_empty(){            return Err("Stack is empty");        }//! This is the build script for both tests7 and tests8.
  2. //!
  3. //! You should modify this file to make both exercises pass.
  4. fn main() {
  5.     // In tests7, we should set up an environment variable
  6.     // called `TEST_FOO`. Print in the standard output to let
  7.     // Cargo do it.
  8.     let timestamp = std::time::SystemTime::now()
  9.         .duration_since(std::time::UNIX_EPOCH)
  10.         .unwrap()
  11.         .as_secs(); // What's the use of this timestamp here?
  12.     let your_command = format!(
  13.         "rustc-env=TEST_FOO={}",
  14.         timestamp.to_string()
  15.     );
  16.     println!("cargo:{}", your_command);
  17.     // In tests8, we should enable "pass" feature to make the
  18.     // testcase return early. Fill in the command to tell
  19.     // Cargo about that.
  20.     // let your_command = "Your command here, please checkout exercises/tests/build.rs";
  21.     // println!("cargo:{}", your_command);
  22. }        self.flag = match self.flag {            SelectedQueue::Q1 => SelectedQueue::Q2,            SelectedQueue::Q2 => SelectedQueue::Q1,        };        Ok(elem)    }    pub fn is_empty(&self) -> bool {                //TODO        match self.flag{            SelectedQueue::Q1 => self.q1.is_empty(),            SelectedQueue::Q2 => self.q2.is_empty(),        }    }}#[cfg(test)]mod tests {        use super::*;                #[test]        fn test_queue(){                let mut s = myStack::::new();                assert_eq!(s.pop(), Err("Stack is empty"));        s.push(1);        s.push(2);        s.push(3);        assert_eq!(s.pop(), Ok(3));        assert_eq!(s.pop(), Ok(2));        s.push(4);        s.push(5);        assert_eq!(s.is_empty(), false);        assert_eq!(s.pop(), Ok(5));        assert_eq!(s.pop(), Ok(4));        assert_eq!(s.pop(), Ok(1));        assert_eq!(s.pop(), Err("Stack is empty"));        assert_eq!(s.is_empty(), true);        }}
复制代码
algorithm9

堆的维护,一如既往地尿流到哪,沟就挖到哪.
数据结构堆(Heap)详解-堆的建立、插入、删除、最大堆、最小堆、堆排序等_最大堆 heap 是一个什么样的存在?-CSDN博客
  1. /*
  2.         dfs
  3.         This problem requires you to implement a basic DFS traversal
  4. */
  5. // I AM NOT DONE
  6. use std::collections::HashSet;
  7. use std::collections::VecDeque;
  8. struct Graph {
  9.     adj: Vec<Vec<usize>>,
  10. }
  11. impl Graph {
  12.     fn new(n: usize) -> Self {
  13.         Graph {
  14.             adj: vec![vec![]; n],
  15.         }
  16.     }
  17.     fn add_edge(&mut self, src: usize, dest: usize) {
  18.         self.adj[src].push(dest);
  19.         self.adj[dest].push(src);
  20.     }
  21.     fn dfs_util(&self, v: usize, visited: &mut HashSet<usize>, visit_order: &mut Vec<usize>) {
  22.         //TODO
  23.         let mut cur = v;  // 当前指向的指针
  24.         visit_order.push(cur);
  25.         visited.insert(cur);
  26.         loop{
  27.             let mut cnt = 0;
  28.             for i in &self.adj[cur]{
  29.                 if !visited.contains(i){
  30.                     visit_order.push(*i);
  31.                     visited.insert(*i);
  32.                     cur = *i;
  33.                     break;
  34.                 }
  35.                 cnt+=1;
  36.             }
  37.             if cnt>=self.adj[cur].len(){
  38.                 if cur==v{
  39.                     break;
  40.                 }
  41.                 for i in (0..visit_order.len()).rev(){
  42.                     cur = visit_order[i];
  43.                 }
  44.             }
  45.         }
  46.     }
  47.     // Perform a depth-first search on the graph, return the order of visited nodes
  48.     fn dfs(&self, start: usize) -> Vec<usize> {
  49.         let mut visited = HashSet::new();
  50.         let mut visit_order = Vec::new();
  51.         self.dfs_util(start, &mut visited, &mut visit_order);
  52.         visit_order
  53.     }
  54. }
  55. #[cfg(test)]
  56. mod tests {
  57.     use super::*;
  58.     #[test]
  59.     fn test_dfs_simple() {
  60.         let mut graph = Graph::new(3);
  61.         graph.add_edge(0, 1);
  62.         graph.add_edge(1, 2);
  63.         let visit_order = graph.dfs(0);
  64.         assert_eq!(visit_order, vec![0, 1, 2]);
  65.     }
  66.     #[test]
  67.     fn test_dfs_with_cycle() {
  68.         let mut graph = Graph::new(4);
  69.         graph.add_edge(0, 1);
  70.         graph.add_edge(0, 2);
  71.         graph.add_edge(1, 2);
  72.         graph.add_edge(2, 3);
  73.         graph.add_edge(3, 3);
  74.         let visit_order = graph.dfs(0);
  75.         assert_eq!(visit_order, vec![0, 1, 2, 3]);
  76.     }
  77.     #[test]
  78.     fn test_dfs_disconnected_graph() {
  79.         let mut graph = Graph::new(5);
  80.         graph.add_edge(0, 1);
  81.         graph.add_edge(0, 2);
  82.         graph.add_edge(3, 4);
  83.         let visit_order = graph.dfs(0);
  84.         assert_eq!(visit_order, vec![0, 1, 2]);
  85.         let visit_order_disconnected = graph.dfs(3);
  86.         assert_eq!(visit_order_disconnected, vec![3, 4]);
  87.     }
  88. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册