温度单位转换

  1. 简陋的转换: ```rust fn main() { let mut t: f64 = 0.;

    let to_type = ‘c’;

    t = trans_temperature(t, to_type); println!(“{}”, t); }

fn trans_temperature(t: f64, to_type: char) -> f64 { if to_type == ‘c’ { (t - 32.) / 1.8 } else { t * 1.8 + 32. }
}

  1. 2. 写得更结构化和 Rust 风格一些:
  2. ```rust
  3. fn main() {
  4. let mut t: Unit = Unit::Celsius(0.);
  5. println!("given tempreture: {:?}", t);
  6. // Celsius => Fahrenheit
  7. t = trans_temperature(t);
  8. println!("then trans to: {:?}", t);
  9. // Fahrenheit => Celsius
  10. t = trans_temperature(t);
  11. println!("and trans back: {:?}", t);
  12. let t = 100.;
  13. println!("\nsimply combine `method` with `match pattern`:");
  14. println!("{}℉ => {:?}", t, Unit::Fahrenheit(t).trans_temperature());
  15. println!("{}°C => {:?}", t, Unit::Celsius(t).trans_temperature());
  16. }
  17. // 打印结果:
  18. // given tempreture: Celsius(0.0)
  19. // then trans to: Fahrenheit(-17.77777777777778)
  20. // and trans back: Celsius(0.0)
  21. //
  22. // simply combine `method` with `match pattern`:
  23. // 100℉ => Celsius(212.0)
  24. // 100°C => Fahrenheit(37.77777777777778)
  25. #[derive(Debug)]
  26. enum Unit {
  27. Celsius(f64),
  28. Fahrenheit(f64),
  29. }
  30. fn trans_temperature(t: Unit) -> Unit {
  31. match t {
  32. Unit::Celsius(x) => Unit::Fahrenheit((x - 32.) / 1.8),
  33. Unit::Fahrenheit(x) => Unit::Celsius(x * 1.8 + 32.),
  34. }
  35. }
  36. impl Unit {
  37. fn trans_temperature(self) -> Self {
  38. match self {
  39. Unit::Celsius(x) => Unit::Fahrenheit((x - 32.) / 1.8),
  40. Unit::Fahrenheit(x) => Unit::Celsius(x * 1.8 + 32.),
  41. }
  42. }
  43. }

斐波那契数列

  1. 简单、不完善并且低效的递归: ```rust fn main() { let n: u64 = 20; let fib: u64 = recurssive_fibonacci(n); println!(“n = {}, fib = {}”, n, fib);

    let v = (1..n + 1).map(|x| recurssive_fibonacci(x)).collect::>(); println!(“{:?}”, v); }

fn recurssive_fibonacci(n: u64) -> u64 { if n < 2 { n } else { recurssive_fibonacci(n - 1) + recurssive_fibonacci(n - 2) } }

  1. 2. if 换成表达式的版本:[https://benjaminbrandt.com/fibonacci-in-rust/](https://benjaminbrandt.com/fibonacci-in-rust/)
  2. ```rust
  3. fn recurssive_fibonacci(n: u32) -> u32 {
  4. match n {
  5. 0 => 1,
  6. 1 => 1,
  7. _ => fibonacci(n - 1) + fibonacci(n - 2),
  8. }
  9. }
  1. 简单、速度更快一些的循环: ```rust fn main() { let n: u64 = 90; let fib: u64 = for_fibonacci(n); println!(“n = {}, fib = {}”, n, fib); // 迭代器列表推导 let v = (1..n + 1).map(|x| for_fibonacci(x)).collect::>(); println!(“{:?}”, v); }

fn forfibonacci(n: u64) -> u64 { let mut a: u64 = 0; let mut b: u64 = 1; let mut c: u64 = a + b; if n == 0 { println!(“n = {} not a positive number”, n); } else { for in 1..n { c = a + b; a = b; b = c; } } c }

  1. 4. 高效迭代器、结构体、trait:来自 [eliovir/rust-examples/fibonacci.rs](https://github.com/eliovir/rust-examples/blob/master/fibonacci.rs)
  2. ```rust
  3. fn main() {
  4. let n: usize = 90;
  5. let fib: u64 = iterative_fibonacci().take(n).last().unwrap();
  6. println!("n = {}, fib = {}", n, fib);
  7. // 迭代器列表推导
  8. let v = (1..n + 1) ‣v: Vec<u64> ‣Range<usize>
  9. .map(|x| iterative_fibonacci().take(x).last().unwrap())
  10. .collect::<Vec<u64>>()
  11. println!("{:?}", v);
  12. }
  13. /// src: https://github.com/rust-lang/rust-by-example
  14. struct Fibonacci {
  15. curr: u64,
  16. next: u64,
  17. }
  18. impl Iterator for Fibonacci {
  19. type Item = u64;
  20. fn next(&mut self) -> Option<u64> {
  21. let new_next = self.curr + self.next;
  22. self.curr = self.next;
  23. self.next = new_next;
  24. Some(self.curr)
  25. }
  26. }

todo

  • 整合三种函数到结构体和 trait 上
  • 基准测试
  1. ❤❤ 宏编程的版本:https://github.com/DanielKeep/rust-recurrence/blob/master/src/lib.rs

这个版本的强大之处:

  1. 直观易读,利用宏编程创造“新语法”:[ fib[n]: u64 = 0, 1 ... fib[n-1] + fib[n-2] ] 初始值和运算规则一目了然。
  2. 可以计算任意相邻两项表达式的结果。修改一个加号就能计算相减的结果
    recurrence![ fib[n]: u64 = 0, 1 ... fib[n-1] - fib[n-2] ]
  3. 可以修改数据类型,让相邻两项的任何表达式作用于任何类型。比如小数
    recurrence![ fib[n]: f64 = 0.0, 1.0 ... fib[n-1] - fib[n-2] ]
  4. 通过“重载”运算符,结合上面两项功能,定义你自己数据类型和运算规则。轻松实现复数版斐波那契数列。
  5. 背后是高效的迭代器,内存占用少、运算速度快。 ```rust

    [macro_use] extern crate recurrence;

fn main() { let fib = recurrence![ fib[n]: u64 = 0, 1 … fib[n-1] + fib[n-2] ]; let fib10: Vec<> = fib.take(10).collect(); assert_eq!(&*fib_10, &[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]); }

  1. <a name="gavYv"></a>
  2. # Twelve Days of Christmas
  3. 1. 笔者的写法:
  4. ```rust
  5. fn main() {
  6. let verse_ordinal: Vec<&str> =
  7. "first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth"
  8. .split(" ")
  9. .collect();
  10. let verse_cardinal: Vec<&str> = "a two three four five six seven eight nine ten elecen twelve"
  11. .split(" ")
  12. .collect();
  13. let verse_stuff: Vec<&str> =
  14. "partridge in a pear tree_turtle doves_french hens_calling birds_gold rings_geese a-laying_swans a-swimming_maids a-milking_ladies dancing_lords a-leaping_pipers piping_drummers drumming"
  15. .split("_")
  16. .collect();
  17. let n: usize = 3;
  18. // 测试第 n 天
  19. // sing(n - 1, &verse_ordinal, &verse_cardinal, &verse_stuff);
  20. // 从第 1 天到第 n 天
  21. for i in 0..n {
  22. sing(i, &verse_ordinal, &verse_cardinal, &verse_stuff);
  23. }
  24. }
  25. fn sing(n: usize, vo: &Vec<&str>, vc: &Vec<&str>, vs: &Vec<&str>) {
  26. println!("On the {} day of Christmas my true love gave to me:", vo[n]);
  27. if n == 0 {
  28. println!("{} {}.\n", vc[n], vs[n]);
  29. } else {
  30. for i in (0..n + 1).rev() {
  31. if i > 0 {
  32. println!("{} {},", vc[i], vs[i]);
  33. } else {
  34. println!("and {} {}.\n", vc[i], vs[i]);
  35. }
  36. }
  37. }
  38. }

打印结果:

  1. On the first day of Christmas my true love gave to me:
  2. a partridge in a pear tree.
  3. On the second day of Christmas my true love gave to me:
  4. two turtle doves,
  5. and a partridge in a pear tree.
  6. On the third day of Christmas my true love gave to me:
  7. three french hens,
  8. two turtle doves,
  9. and a partridge in a pear tree.
  1. 其他人的写法:https://benjaminbrandt.com/twelve-days-of-christmas-in-rust/

数组结构拆分成业务逻辑的函数:开头、中间、结尾具有不同形式,联系的纽带是第 n 天

  1. fn day_intro(n: u32) {
  2. let day = match n {
  3. 1 => "first",
  4. 2 => "second",
  5. 3 => "third",
  6. 4 => "fourth",
  7. 5 => "fifth",
  8. 6 => "sixth",
  9. 7 => "seventh",
  10. 8 => "eighth",
  11. 9 => "ninth",
  12. 10 => "tenth",
  13. 11 => "eleventh",
  14. 12 => "twelfth",
  15. _ => "",
  16. };
  17. println!(
  18. "\nOn the {} day of Christmas\nmy true love sent to me:",
  19. day
  20. );
  21. }
  22. fn gift(n: u32, prefix: &str) {
  23. let gift_text = match n {
  24. 1 => "a Partridge in a Pear Tree",
  25. 2 => "Two Turtle Doves",
  26. 3 => "Three French Hens",
  27. 4 => "Four Calling Birds",
  28. 5 => "Five Golden Rings",
  29. 6 => "Six Geese a Laying",
  30. 7 => "Seven Swans a Swimming",
  31. 8 => "Eight Maids a Milking",
  32. 9 => "Nine Ladies Dancing",
  33. 10 => "Ten Lords a Leaping",
  34. 11 => "Eleven Pipers Piping",
  35. 12 => "12 Drummers Drumming",
  36. _ => "",
  37. };
  38. println!("{}{}", prefix, gift_text);
  39. }
  40. fn main() {
  41. println!("TWELVE DAYS OF CHRISTMAS:");
  42. for day in 1..13 {
  43. day_intro(day);
  44. for gift_day in (1..(day + 1)).rev() {
  45. gift(
  46. gift_day,
  47. if gift_day == 1 && day != 1 {
  48. "and "
  49. } else {
  50. ""
  51. },
  52. );
  53. }
  54. }
  55. }

vec 的平均数、中位数、众数

Cargo.toml 添加以下依赖:

  1. [dependencies]
  2. fraction = "0.8.0"
  3. rand = "0.8.3"

src/main.rs 内容:

  1. use fraction::{Fraction, ToPrimitive};
  2. use rand::{thread_rng, Rng};
  3. use std::collections::HashMap;
  4. fn main() {
  5. // let mut v: Vec<f64> = vec![1., -1., 100., 1., 36., 100.];
  6. let mut v: Vec<f64> = (0..10).map(|_| thread_rng().gen_range(-5.0..5.0)).collect();
  7. println!("the initial vec: \n{:?}\n", v);
  8. println!("average: {}", average(&v));
  9. println!("middle number: {}", median(&mut v));
  10. let (mode_num, cnt) = mode(&v);
  11. println!("mode number: {}, count: {}", mode_num, cnt);
  12. }
  13. fn average(v: &Vec<f64>) -> f64 {
  14. v.iter().sum::<f64>() / v.len() as f64
  15. }
  16. fn median(v: &mut Vec<f64>) -> f64 {
  17. v.sort_by(|a, b| a.partial_cmp(b).unwrap()); // f64 只支持 partial_cmp,注意 v 已经被排序了
  18. // println!("the sorted vec: {:?}", v);
  19. let pos1: usize = v.len() / 2;
  20. if v.len() % 2 == 0 {
  21. (v[pos1] + v[pos1 - 1]) / 2. // pos1 >= 1
  22. } else {
  23. v[pos1]
  24. }
  25. }
  26. fn mode(v: &Vec<f64>) -> (f64, u64) {
  27. let mut map = HashMap::new();
  28. // 注意 Vec 对 f64/f32 不支持 `Eq`,无法直接计数,因此这里转换成支持 `Eq` 的 Fraction 类型
  29. let f: Vec<Fraction> = v.iter().map(|&x| Fraction::from(x)).collect();
  30. // 对 vec 元素计数
  31. for ff in f {
  32. *map.entry(ff).or_insert(0) += 1;
  33. }
  34. // 对 hashmap 按照 value (即个数)排序,多个最大值只返回最后一个
  35. let item = map.iter().max_by_key(|entry| entry.1).unwrap();
  36. (item.0.to_f64().unwrap(), *item.1)
  37. }
  • 最简单的版本是以 Vec<i32> 类型为范本,我也是参考了里面的代码框架:stackexchange: calculate-mean-median-and-mode-in-rust
  • 而我写的版本针对 Vec<f64> 类型,而 f64 之类的浮点数不支持比较,即 OrdEq not implemented,所以在数组排序浮点元素计数上麻烦了一点。而这也正说明不同类型需要不同的处理方式,我们必须时刻思考和知道每一步的数据是什么类型,才能进行往后的处理。
  • 当然,这么常见的需求肯定有现成的工具,比如这个对大型数据流支持基本的统计函数 crate:https://github.com/BurntSushi/rust-stats ,支持以下函数:

    1. mean Compute the mean of a stream in constant space.
    2. median Compute the exact median on a stream of data.
    3. merge_all Merges all items in the stream.
    4. mode Compute the exact mode on a stream of data.
    5. modes Compute the modes on a stream of data.
    6. stddev Compute the standard deviation of a stream in constant space.variance Compute the variance of a stream in constant space.

    Cargo.toml 中的依赖:

    1. [dependencies]
    2. streaming-stats = "0.2.3"
    3. rand = "0.8.3"

    src/main.rs 内容:

    1. use rand::{thread_rng, Rng};
    2. use stats;
    3. fn main() {
    4. const N: usize = 20;
    5. let v: Vec<i64> = (0..N).map(|_| thread_rng().gen_range(-5..6)).collect();
    6. println!("the initial vec: \n{:?}\n", v);
    7. println!("stats average: {}", stats::mean(v.iter().copied()));
    8. println!("stats median: {:?}", stats::median(v.iter().copied()));
    9. println!("stats modes: {:?}", stats::modes(v.iter().copied()));
    10. println!("stats the exact mode: {:?}", stats::mode(v.iter().copied()));
    11. println!("stats stddev: {:?}", stats::stddev(v.iter().copied()));
    12. println!("stats variance: {:?}\n", stats::variance(v.iter().copied()));
    13. let mut freq: stats::Frequencies<i64> = stats::Frequencies::new();
    14. for ele in &v {
    15. freq.add(*ele);
    16. }
    17. println!("频数 HashMap:{:?}", freq);
    18. println!("元素个数:{:?}", freq.len());
    19. println!("获取计数:{:?}", freq.count(&0));
    20. println!("获取众数:{:?}", freq.mode());
    21. println!("按元素及其计数降序返回元组:{:?}", freq.most_frequent());
    22. println!("按元素及其计数升序返回元组:{:?}", freq.least_frequent());
    23. }

    打印结果:

    1. the initial vec:
    2. [-4, 5, -5, 1, 1, 3, -3, 2, 0, -3, -4, 5, 1, 2, -1, -3, 1, 4, 2, -1]
    3. stats average: 0.14999999999999997
    4. stats median: Some(1.0)
    5. stats modes: [1]
    6. stats the exact mode: Some(1)
    7. stats stddev: 2.971110903349116
    8. stats variance: 8.8275
    9. 频数 HashMap:{-3: 3, 2: 3, 3: 1, -1: 2, 4: 1, 0: 1, 5: 2, -5: 1, -4: 2, 1: 4}
    10. 元素个数:10
    11. 获取计数:1
    12. 获取众数:Some(1)
    13. 按元素及其计数降序返回元组:[(1, 4), (-3, 3), (2, 3), (-1, 2), (5, 2), (-4, 2), (3, 1), (4, 1), (0, 1), (-5, 1)]
    14. 按元素及其计数升序返回元组:[(3, 1), (4, 1), (0, 1), (-5, 1), (-1, 2), (5, 2), (-4, 2), (-3, 3), (2,3), (1, 4)]

    pig_latin

    将字符串转换为 Pig Latin,也就是每一个单词的第一个辅音字母被移动到单词的结尾并增加 “ay”,所以 “first” 会变成 “irst-fay”。元音字母开头的单词则在结尾增加 “hay”(“apple” 会变成 “apple-hay”)。

    1. use std::io;
    2. fn main() {
    3. let mut word = input();
    4. println!("{}", pig_latin(&mut word));
    5. }
    6. fn pig_latin(word: &mut String) -> String {
    7. let pat: Vec<&str> = "a e i o u A E I O U".split(" ").collect();
    8. let word_tail = word.split_off(1); // 注意此处直接修改了 word
    9. if pat.contains(&word.as_str()) {
    10. format!("{}{}-hay", word, word_tail)
    11. } else {
    12. format!("{}-{}ay", word_tail, word)
    13. }
    14. }
    15. fn input() -> String {
    16. let mut input_ = String::new();
    17. io::stdin()
    18. .read_line(&mut input_)
    19. .expect("Failed to read from stdin");
    20. input_.trim().to_string()
    21. }

    输入和查询部门成员

    使用 HashMap 和 vector,创建一个文本接口来允许用户向公司的部门中增加员工的名字。例如,“Add Sally to Engineering” 或 “Add Amir to Sales”。接着让用户获取一个部门的所有员工的列表,或者公司每个部门的所有员工按照字典序排列的列表。

    1. use std::collections::HashMap;
    2. fn main() {
    3. let mut info: HashMap<String, Vec<String>> = HashMap::new();
    4. let s = "Add Sally to Engineering".to_string();
    5. push_info(&mut info, &s);
    6. let s = "Add Allice to Engineering".to_string();
    7. push_info(&mut info, &s);
    8. let s = "Add Allen to Engineering".to_string();
    9. push_info(&mut info, &s);
    10. let s = "Add Andy to Marketing".to_string();
    11. push_info(&mut info, &s);
    12. println!("{:#?}", info);
    13. println!("choose the department below:\n{:?}", &info.keys());
    14. let department = "Engineering".to_string();
    15. println!(
    16. "the sorted names in {}:\n{:?}",
    17. department,
    18. search_info(&info, &department)
    19. );
    20. }
    21. fn parse_info(s: &String) -> [String; 2] {
    22. let capture_name = s.find(" to ").unwrap();
    23. let capture_department = capture_name + 4;
    24. let name = s[4..capture_name].to_string();
    25. let department = s[capture_department..].to_string();
    26. [name, department] // 当然,也可以定义一个结构体
    27. }
    28. fn push_info(info: &mut HashMap<String, Vec<String>>, s: &String) {
    29. let [name, department] = parse_info(s);
    30. let vec_names = info.entry(department).or_insert(Vec::new());
    31. vec_names.push(name);
    32. }
    33. fn search_info(info: &HashMap<String, Vec<String>>, department: &String) -> Vec<String> {
    34. let mut vec_names = info.get(department).unwrap().to_vec();
    35. vec_names.sort();
    36. vec_names
    37. }

    打印结果:

    1. {
    2. "Marketing": [
    3. "Andy",
    4. ],
    5. "Engineering": [
    6. "Sally",
    7. "Allice",
    8. "Allen",
    9. ],
    10. }
    11. choose the department below:
    12. ["Marketing", "Engineering"]
    13. the sorted names in Engineering:
    14. ["Allen", "Allice", "Sally"]