温度单位转换
简陋的转换: ```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.
}
}
2. 写得更结构化和 Rust 风格一些:```rustfn main() {let mut t: Unit = Unit::Celsius(0.);println!("given tempreture: {:?}", t);// Celsius => Fahrenheitt = trans_temperature(t);println!("then trans to: {:?}", t);// Fahrenheit => Celsiust = trans_temperature(t);println!("and trans back: {:?}", t);let t = 100.;println!("\nsimply combine `method` with `match pattern`:");println!("{}℉ => {:?}", t, Unit::Fahrenheit(t).trans_temperature());println!("{}°C => {:?}", t, Unit::Celsius(t).trans_temperature());}// 打印结果:// given tempreture: Celsius(0.0)// then trans to: Fahrenheit(-17.77777777777778)// and trans back: Celsius(0.0)//// simply combine `method` with `match pattern`:// 100℉ => Celsius(212.0)// 100°C => Fahrenheit(37.77777777777778)#[derive(Debug)]enum Unit {Celsius(f64),Fahrenheit(f64),}fn trans_temperature(t: Unit) -> Unit {match t {Unit::Celsius(x) => Unit::Fahrenheit((x - 32.) / 1.8),Unit::Fahrenheit(x) => Unit::Celsius(x * 1.8 + 32.),}}impl Unit {fn trans_temperature(self) -> Self {match self {Unit::Celsius(x) => Unit::Fahrenheit((x - 32.) / 1.8),Unit::Fahrenheit(x) => Unit::Celsius(x * 1.8 + 32.),}}}
斐波那契数列
简单、不完善并且低效的递归: ```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) } }
2. 把 if 换成表达式的版本:[https://benjaminbrandt.com/fibonacci-in-rust/](https://benjaminbrandt.com/fibonacci-in-rust/)```rustfn recurssive_fibonacci(n: u32) -> u32 {match n {0 => 1,1 => 1,_ => fibonacci(n - 1) + fibonacci(n - 2),}}
- 简单、速度更快一些的循环:
```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 }
4. ❤ 高效迭代器、结构体、trait:来自 [eliovir/rust-examples/fibonacci.rs](https://github.com/eliovir/rust-examples/blob/master/fibonacci.rs)```rustfn main() {let n: usize = 90;let fib: u64 = iterative_fibonacci().take(n).last().unwrap();println!("n = {}, fib = {}", n, fib);// 迭代器列表推导let v = (1..n + 1) ‣v: Vec<u64> ‣Range<usize>.map(|x| iterative_fibonacci().take(x).last().unwrap()).collect::<Vec<u64>>()println!("{:?}", v);}/// src: https://github.com/rust-lang/rust-by-examplestruct Fibonacci {curr: u64,next: u64,}impl Iterator for Fibonacci {type Item = u64;fn next(&mut self) -> Option<u64> {let new_next = self.curr + self.next;self.curr = self.next;self.next = new_next;Some(self.curr)}}
todo
- 整合三种函数到结构体和 trait 上
- 基准测试
这个版本的强大之处:
- 直观易读,利用宏编程创造“新语法”:
[ fib[n]: u64 = 0, 1 ... fib[n-1] + fib[n-2] ]初始值和运算规则一目了然。 - 可以计算任意相邻两项表达式的结果。修改一个加号就能计算相减的结果
recurrence![ fib[n]: u64 = 0, 1 ... fib[n-1] - fib[n-2] ]。 - 可以修改数据类型,让相邻两项的任何表达式作用于任何类型。比如小数
recurrence![ fib[n]: f64 = 0.0, 1.0 ... fib[n-1] - fib[n-2] ]。 - 通过“重载”运算符,结合上面两项功能,定义你自己数据类型和运算规则。轻松实现复数版斐波那契数列。
- 背后是高效的迭代器,内存占用少、运算速度快。
```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]); }
<a name="gavYv"></a># Twelve Days of Christmas1. 笔者的写法:```rustfn main() {let verse_ordinal: Vec<&str> ="first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth".split(" ").collect();let verse_cardinal: Vec<&str> = "a two three four five six seven eight nine ten elecen twelve".split(" ").collect();let verse_stuff: Vec<&str> ="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".split("_").collect();let n: usize = 3;// 测试第 n 天// sing(n - 1, &verse_ordinal, &verse_cardinal, &verse_stuff);// 从第 1 天到第 n 天for i in 0..n {sing(i, &verse_ordinal, &verse_cardinal, &verse_stuff);}}fn sing(n: usize, vo: &Vec<&str>, vc: &Vec<&str>, vs: &Vec<&str>) {println!("On the {} day of Christmas my true love gave to me:", vo[n]);if n == 0 {println!("{} {}.\n", vc[n], vs[n]);} else {for i in (0..n + 1).rev() {if i > 0 {println!("{} {},", vc[i], vs[i]);} else {println!("and {} {}.\n", vc[i], vs[i]);}}}}
打印结果:
On the first day of Christmas my true love gave to me:a partridge in a pear tree.On the second day of Christmas my true love gave to me:two turtle doves,and a partridge in a pear tree.On the third day of Christmas my true love gave to me:three french hens,two turtle doves,and a partridge in a pear tree.
数组结构拆分成业务逻辑的函数:开头、中间、结尾具有不同形式,联系的纽带是第 n 天
fn day_intro(n: u32) {let day = match n {1 => "first",2 => "second",3 => "third",4 => "fourth",5 => "fifth",6 => "sixth",7 => "seventh",8 => "eighth",9 => "ninth",10 => "tenth",11 => "eleventh",12 => "twelfth",_ => "",};println!("\nOn the {} day of Christmas\nmy true love sent to me:",day);}fn gift(n: u32, prefix: &str) {let gift_text = match n {1 => "a Partridge in a Pear Tree",2 => "Two Turtle Doves",3 => "Three French Hens",4 => "Four Calling Birds",5 => "Five Golden Rings",6 => "Six Geese a Laying",7 => "Seven Swans a Swimming",8 => "Eight Maids a Milking",9 => "Nine Ladies Dancing",10 => "Ten Lords a Leaping",11 => "Eleven Pipers Piping",12 => "12 Drummers Drumming",_ => "",};println!("{}{}", prefix, gift_text);}fn main() {println!("TWELVE DAYS OF CHRISTMAS:");for day in 1..13 {day_intro(day);for gift_day in (1..(day + 1)).rev() {gift(gift_day,if gift_day == 1 && day != 1 {"and "} else {""},);}}}
vec 的平均数、中位数、众数
Cargo.toml 添加以下依赖:
[dependencies]fraction = "0.8.0"rand = "0.8.3"
src/main.rs 内容:
use fraction::{Fraction, ToPrimitive};use rand::{thread_rng, Rng};use std::collections::HashMap;fn main() {// let mut v: Vec<f64> = vec![1., -1., 100., 1., 36., 100.];let mut v: Vec<f64> = (0..10).map(|_| thread_rng().gen_range(-5.0..5.0)).collect();println!("the initial vec: \n{:?}\n", v);println!("average: {}", average(&v));println!("middle number: {}", median(&mut v));let (mode_num, cnt) = mode(&v);println!("mode number: {}, count: {}", mode_num, cnt);}fn average(v: &Vec<f64>) -> f64 {v.iter().sum::<f64>() / v.len() as f64}fn median(v: &mut Vec<f64>) -> f64 {v.sort_by(|a, b| a.partial_cmp(b).unwrap()); // f64 只支持 partial_cmp,注意 v 已经被排序了// println!("the sorted vec: {:?}", v);let pos1: usize = v.len() / 2;if v.len() % 2 == 0 {(v[pos1] + v[pos1 - 1]) / 2. // pos1 >= 1} else {v[pos1]}}fn mode(v: &Vec<f64>) -> (f64, u64) {let mut map = HashMap::new();// 注意 Vec 对 f64/f32 不支持 `Eq`,无法直接计数,因此这里转换成支持 `Eq` 的 Fraction 类型let f: Vec<Fraction> = v.iter().map(|&x| Fraction::from(x)).collect();// 对 vec 元素计数for ff in f {*map.entry(ff).or_insert(0) += 1;}// 对 hashmap 按照 value (即个数)排序,多个最大值只返回最后一个let item = map.iter().max_by_key(|entry| entry.1).unwrap();(item.0.to_f64().unwrap(), *item.1)}
- 最简单的版本是以
Vec<i32>类型为范本,我也是参考了里面的代码框架:stackexchange: calculate-mean-median-and-mode-in-rust - 而我写的版本针对
Vec<f64>类型,而f64之类的浮点数不支持比较,即Ord和Eqnot implemented,所以在数组排序和浮点元素计数上麻烦了一点。而这也正说明不同类型需要不同的处理方式,我们必须时刻思考和知道每一步的数据是什么类型,才能进行往后的处理。 当然,这么常见的需求肯定有现成的工具,比如这个对大型数据流支持基本的统计函数 crate:https://github.com/BurntSushi/rust-stats ,支持以下函数:
mean Compute the mean of a stream in constant space.median Compute the exact median on a stream of data.merge_all Merges all items in the stream.mode Compute the exact mode on a stream of data.modes Compute the modes on a stream of data.stddev Compute the standard deviation of a stream in constant space.variance Compute the variance of a stream in constant space.
Cargo.toml中的依赖:[dependencies]streaming-stats = "0.2.3"rand = "0.8.3"
src/main.rs内容:use rand::{thread_rng, Rng};use stats;fn main() {const N: usize = 20;let v: Vec<i64> = (0..N).map(|_| thread_rng().gen_range(-5..6)).collect();println!("the initial vec: \n{:?}\n", v);println!("stats average: {}", stats::mean(v.iter().copied()));println!("stats median: {:?}", stats::median(v.iter().copied()));println!("stats modes: {:?}", stats::modes(v.iter().copied()));println!("stats the exact mode: {:?}", stats::mode(v.iter().copied()));println!("stats stddev: {:?}", stats::stddev(v.iter().copied()));println!("stats variance: {:?}\n", stats::variance(v.iter().copied()));let mut freq: stats::Frequencies<i64> = stats::Frequencies::new();for ele in &v {freq.add(*ele);}println!("频数 HashMap:{:?}", freq);println!("元素个数:{:?}", freq.len());println!("获取计数:{:?}", freq.count(&0));println!("获取众数:{:?}", freq.mode());println!("按元素及其计数降序返回元组:{:?}", freq.most_frequent());println!("按元素及其计数升序返回元组:{:?}", freq.least_frequent());}
打印结果:
the initial vec:[-4, 5, -5, 1, 1, 3, -3, 2, 0, -3, -4, 5, 1, 2, -1, -3, 1, 4, 2, -1]stats average: 0.14999999999999997stats median: Some(1.0)stats modes: [1]stats the exact mode: Some(1)stats stddev: 2.971110903349116stats variance: 8.8275频数 HashMap:{-3: 3, 2: 3, 3: 1, -1: 2, 4: 1, 0: 1, 5: 2, -5: 1, -4: 2, 1: 4}元素个数:10获取计数:1获取众数:Some(1)按元素及其计数降序返回元组:[(1, 4), (-3, 3), (2, 3), (-1, 2), (5, 2), (-4, 2), (3, 1), (4, 1), (0, 1), (-5, 1)]按元素及其计数升序返回元组:[(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”)。
use std::io;fn main() {let mut word = input();println!("{}", pig_latin(&mut word));}fn pig_latin(word: &mut String) -> String {let pat: Vec<&str> = "a e i o u A E I O U".split(" ").collect();let word_tail = word.split_off(1); // 注意此处直接修改了 wordif pat.contains(&word.as_str()) {format!("{}{}-hay", word, word_tail)} else {format!("{}-{}ay", word_tail, word)}}fn input() -> String {let mut input_ = String::new();io::stdin().read_line(&mut input_).expect("Failed to read from stdin");input_.trim().to_string()}
输入和查询部门成员
使用 HashMap 和 vector,创建一个文本接口来允许用户向公司的部门中增加员工的名字。例如,“Add Sally to Engineering” 或 “Add Amir to Sales”。接着让用户获取一个部门的所有员工的列表,或者公司每个部门的所有员工按照字典序排列的列表。
use std::collections::HashMap;fn main() {let mut info: HashMap<String, Vec<String>> = HashMap::new();let s = "Add Sally to Engineering".to_string();push_info(&mut info, &s);let s = "Add Allice to Engineering".to_string();push_info(&mut info, &s);let s = "Add Allen to Engineering".to_string();push_info(&mut info, &s);let s = "Add Andy to Marketing".to_string();push_info(&mut info, &s);println!("{:#?}", info);println!("choose the department below:\n{:?}", &info.keys());let department = "Engineering".to_string();println!("the sorted names in {}:\n{:?}",department,search_info(&info, &department));}fn parse_info(s: &String) -> [String; 2] {let capture_name = s.find(" to ").unwrap();let capture_department = capture_name + 4;let name = s[4..capture_name].to_string();let department = s[capture_department..].to_string();[name, department] // 当然,也可以定义一个结构体}fn push_info(info: &mut HashMap<String, Vec<String>>, s: &String) {let [name, department] = parse_info(s);let vec_names = info.entry(department).or_insert(Vec::new());vec_names.push(name);}fn search_info(info: &HashMap<String, Vec<String>>, department: &String) -> Vec<String> {let mut vec_names = info.get(department).unwrap().to_vec();vec_names.sort();vec_names}
打印结果:
{"Marketing": ["Andy",],"Engineering": ["Sally","Allice","Allen",],}choose the department below:["Marketing", "Engineering"]the sorted names in Engineering:["Allen", "Allice", "Sally"]
