Rust 编程小技巧(7)
1. 交换变量
与python, go等语言用法类似,不同的是rust不能省掉元组的括号 () 。
fn main() { let a = 3; let b = 23; println!("a: {}, b: {}", a, b); let (a, b) = (b, a); println!("a: {}, b: {}", a, b); }
输出:
a: 3, b: 23
a: 23, b: 3
2. 翻转数组
fn main() { let x = vec!["Hello", "World"]; let y: Vec<_> = x.iter().rev().collect(); println!("{:?}\n{:?}", x, y); let mut z = vec![1,2,3]; println!("{:?}", z); z.reverse(); println!("{:?}", z); }
输出:
["Hello", "World"]
["World", "Hello"]
[1, 2, 3]
[3, 2, 1]
3. for_each() 用法
fn main() { // 迭代一个 vec 并打印每个元素 let vec = vec![1, 2, 3, 4, 5]; vec.iter().for_each(|x| print!("{} ", x)); println!(); // 迭代一个字符串并打印每个字符 let s = "hello"; s.chars().for_each(|c| print!("{} ", c)); println!(); // 迭代一个 vec 并将其元素加倍 let mut v1 = vec![1, 2, 3, 4, 5]; let mut v2 = vec![]; v1.iter().for_each(|x| v2.push(x * 2)); println!("{:?}", v2); v1.clone().iter().for_each(|x| v1.push(x * 2)); println!("{:?}", v1); }
输出:
1 2 3 4 5
h e l l o
[2, 4, 6, 8, 10]
[1, 2, 3, 4, 5, 2, 4, 6, 8, 10]
4. 结构体 Display trait
结构体的两种形式,对应的成员取法不同;
前者用 self.成员变量名 self.x, self.y;后者用 self.成员索引号 self.0, self.1, self.2, ......
use std::fmt::Display; use std::fmt::Result; use std::fmt::Formatter; struct Point { x: f64, y: f64, } struct Point2(f64, f64); impl Display for Point { fn fmt(&self, f: &mut Formatter<'_>) -> Result { write!(f, "({}, {})", self.x, self.y) } } impl Display for Point2 { fn fmt(&self, f: &mut Formatter<'_>) -> Result { write!(f, "({}, {})", self.0, self.1) } } fn main() { let p = Point { x: 2.0, y: -3.5 }; println!("{}", p); let p = Point2(2.0, -3.5); println!("{}", p); }
输出:
(2, -3.5)
(2, -3.5)
5. HashMap 和 BTreeMap
两者都是 Rust 中的哈希表数据结构,它们的相同点:
都支持使用 Vec 或 String 作为键,也支持使用标准库中的其他结构体作为键。
都支持使用 Option 类型作为键值对中的值。
都支持使用 HashMap 类型的成员函数来进行基本的操作,例如插入、删除、查找、更新等。
不同点:
HashMap 使用哈希表(HashMap)算法来存储键值对,而 BTreeMap 使用 B-TREE(B 树)算法来存储键值对。因此,BTreeMap 在查找、插入、删除等操作上的性能比 HashMap 更好。
如果需要使用哈希表(HashMap)数据结构,但不需要按照键值对的顺序来访问,而且对查找、插入、删除等操作的性能要求不高,那么可以使用 HashMap。如果需要使用哈希表(HashMap)数据结构,而且对查找、插入、删除等操作的性能要求较高,而且需要按照键值对的顺序来访问,那么可以使用 BTreeMap。
示例:
use std::collections::BTreeMap; use std::collections::HashMap; fn main() { let mut x = BTreeMap::new(); x.insert("one", 1); x.insert("two", 2); println!("{:?}", x); let x: HashMap<&str, i32> = [ ("one", 1), ("two", 2), ].iter().cloned().collect(); println!("{:?}", x); }
输出:
{"one": 1, "two": 2}
{"one": 1, "two": 2}
6. 遍历输出哈希表
在for...in...循环结构中使用元组(k, v)读取对应键值对:
use std::collections::BTreeMap; use std::collections::HashMap; fn main() { let mut x = BTreeMap::new(); x.insert("one", 1); x.insert("two", 2); x.insert("three", 3); x.insert("four", 4); for (k, v) in &x { println!("Key={}, Value={}", k, v); } println!(); let x: HashMap<&str, i32> = [ ("one", 1), ("two", 2), ("three", 3), ("four", 4), ].iter().cloned().collect(); for (k, v) in &x { println!("Key={key}, Value={val}", key = k, val = v); } }
输出:
Key=four, Value=4
Key=one, Value=1
Key=three, Value=3
Key=two, Value=2
Key=three, Value=3
Key=two, Value=2
Key=one, Value=1
Key=four, Value=4
7. 分离奇数和偶数
.filter() 方法是一个在标准库中的std::iter::Iterator trait的默认方法。这个方法会创建一个新的迭代器,包含所有满足给定条件的元素。
示例:分离一个数组中的奇数和偶数
fn main() { let mut vec = vec![1, 2, 3, 4, 5]; vec.clone().iter().for_each(|x| vec.push(x + 5)); println!("{:?}", vec); fn is_even(x: &i32) -> bool { *x % 2 == 0 } fn print_x(x: &i32) { print!("{} ", x) } vec.iter().filter(|x| !is_even(x)).for_each(|x| print_x(x)); println!(); vec.iter().filter(|x| is_even(x)).for_each(|x| print_x(x)); println!(); }
输出:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
1 3 5 7 9
2 4 6 8 10
8. 判断素数(质数)
.any() 方法是一个在标准库中的std::iter::Iterator trait的默认方法。这个方法会检查迭代器中是否有元素满足给定的条件,如果有元素满足条件,它就会返回true,否则返回false。
示例:求30以内的质数
fn is_prime(n: u64) -> bool { match n { 0..=1 => false, _ => !(2..n).any(|d| n % d == 0), } } fn main() { for i in 1..=30 { if is_prime(i) { print!("{} ", i); } } println!(); }
输出:
2 3 5 7 11 13 17 19 23 29