1. 生成随机值

  需要安装rand库,可通过cargo add rand命令安装

[dependencies]
rand = "0.8.5"

1.1 生成随机数

  在随机数生成器 rand::Rng 的帮助下,通过 rand::thread_rng 生成随机数。可以开启多个线程,每个线程都有一个初始化的生成器。整数在其类型范围内均匀分布,浮点数是从 0均匀分布到 1,但不包括 1

use rand::Rng;

fn main() {
let mut rng = rand::thread_rng();

let n1: u8 = rng.gen();
let n2: u16 = rng.gen();
println!("随机生成 u8: {}", n1);
println!("随机生成 u16: {}", n2);
println!("随机生成 u32: {}", rng.gen::<u32>());
println!("随机生成 i32: {}", rng.gen::<i32>());
println!("随机生成 float: {}", rng.gen::<f64>());
}
  • 程序输出结果
随机生成 u8: 158
随机生成 u16: 26703
随机生成 u32: 2989669353
随机生成 i32: -1944070083
随机生成 float: 0.6281595400384855

1.2 生成范围内随机数

  使用 Rng::gen_range,在半开放的 [0, 10) 范围内(不包括 10)生成一个随机值。

use rand::Rng;

fn main() {
let mut rng = rand::thread_rng();
println!("整型Integer: {}", rng.gen_range(0..10));
println!("浮点型Float: {}", rng.gen_range(0.0..10.0));
}
  • 程序输出结果
整型Integer: 7
浮点型Float: 4.609263483162893

  使用 Uniform 模块可以得到均匀分布的值。下述代码和上述代码具有相同的效果,但在相同范围内重复生成数字时,下述代码性能可能会更好。

use rand::distributions::{Distribution, Uniform};

fn main() {
let mut rng = rand::thread_rng();
let die = Uniform::from(1..7);

loop {
let throw = die.sample(&mut rng);
println!("掷骰子: {}", throw);
if throw == 6 {
break;
}
}
}
  • 程序输出结果
掷骰子: 3
掷骰子: 1
掷骰子: 5
掷骰子: 4
掷骰子: 4
掷骰子: 5
掷骰子: 1
掷骰子: 4
掷骰子: 5
掷骰子: 5
掷骰子: 2
掷骰子: 5
掷骰子: 4
掷骰子: 1
掷骰子: 5
掷骰子: 4
掷骰子: 6

1.3 生成给定分布随机数

  默认情况下,随机数在 rand crate 中是均匀分布。rand_distr(可通过cargo add rand_distr 安装) crate 提供其它的分布类型。如要使用,首先实例化一个分布,然后在随机数生成器rand::Rng 的帮助下,使用 Distribution::sample 从该分布中进行采样。如下是一个使用正态(Normal)分布的实例

[dependencies]
rand = "0.8.5"
rand_distr = "0.4.3"
use rand_distr::{Distribution, Normal, NormalError};
use rand::thread_rng;

fn main() -> Result<(), NormalError> {
let mut rng = thread_rng();
let normal = Normal::new(2.0, 3.0)?;
let v = normal.sample(&mut rng);
println!("{} 来自 N(2, 9) 分布", v);
Ok(())
}
  • 程序输出结果
4.025748774397368 来自 N(2, 9) 分布

1.4 生成自定义类型随机值

  随机生成一个元组 (i32, bool, f64) 和用户定义类型为 Point 的变量。为 Standard 实现 Distribution trait,以允许其随机生成。

use rand::Rng;
use rand::distributions::{Distribution, Standard};

#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}

impl Distribution<Point> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
let (rand_x, rand_y) = rng.gen();
Point {
x: rand_x,
y: rand_y,
}
}
}

fn main() {
let mut rng = rand::thread_rng();
let rand_tuple = rng.gen::<(i32, bool, f64)>();
let rand_point: Point = rng.gen();
println!("随机元组: {:?}", rand_tuple);
println!("随机坐标: {:?}", rand_point);
}
  • 程序输出结果
随机元组: (-410099798, true, 0.3339881538362096)
随机坐标: Point { x: 1211748610, y: -959131956 }

1.5 从一组字母数字字符生成随机密码

  随机生成一个给定长度的 ASCII 字符串,范围为 A-Za-z0-9,使用字母数字样本

use rand::{thread_rng, Rng};
use rand::distributions::Alphanumeric;

fn main() {
let rand_string: String = thread_rng()
.sample_iter(&Alphanumeric)
.take(16)
.map(char::from)
.collect();

println!("随机密码: {}", rand_string);
}
  • 程序输出结果
随机密码: bksgkrXebcPo3ZsW

1.6 从一组用户定义字符创建随机密码

  使用用户自定义的字节字符串,使用 gen_range 函数,随机生成一个给定长度的 ASCII 字符串

use rand::Rng;
fn main() {
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789)(*&^%$#@!~";
const PASSWORD_LEN: usize = 16;
let mut rng = rand::thread_rng();

let password: String = (0..PASSWORD_LEN)
.map(|_| {
let idx = rng.gen_range(0..CHARSET.len());
CHARSET[idx] as char
})
.collect();

println!("指定字符随机密码: {}", password);
}
  • 程序输出结果
指定字符随机密码: Rz!eVvWN)Xg5OYae

2. Vector 排序

2.1 整数 Vector 排序

  通过 vec::sort 对一个整数 Vector 进行排序。另一种方法是使用 vec::sort_unstable,后者运行速度更快一些,但不保持相等元素的顺序。

fn main() {
let mut vec = vec![1, 5, 10, 2, 15];

vec.sort();

assert_eq!(vec, vec![1, 2, 5, 10, 15]);
}

2.2 Vector 排序

  对于f32f64vector,可以使用 vec::sort_byPartialOrd::partial_cmp 对其进行排序

fn main() {
let mut vec = vec![1.1, 1.15, 5.5, 1.123, 2.0];

vec.sort_by(|a, b| a.partial_cmp(b).unwrap());

assert_eq!(vec, vec![1.1, 1.123, 1.15, 2.0, 5.5]);
}

2.3 结构体 Vector 排序

  依据自然顺序(按名称和年龄),对具有 nameage 属性的 Person 结构体 Vector 排序。为了使 Person 可排序,需要添加traitsPartialEq。这样也可以使用 vec:sort_by 方法自定义比较函数,如按照年龄排序。

use std::cmp::Ordering;

#[derive(Debug, PartialEq)]
struct Person {
name: String,
age: u32,
salary: f64,
}

impl Person {
pub fn new(name: String, age: u32, salary: f64) -> Self {
Person { name, age, salary }
}
}

fn main() {
let mut people = vec![
Person::new("Zoe".to_string(), 25, 9483.54),
Person::new("Al".to_string(), 60, 2433.64),
Person::new("John".to_string(), 22, 6433.34),
];

// 根据 name 值对 people 进行排序
people.sort_by(|a, b| a.name.cmp(&b.name));
assert_eq!(
people,
vec![
Person::new("Al".to_string(), 60, 2433.64),
Person::new("John".to_string(), 22, 6433.34),
Person::new("Zoe".to_string(), 25, 9483.54),
]
);

// 根据 age 值对 people 进行排序(从小到大)
people.sort_by(|a, b| a.age.cmp(&b.age));

assert_eq!(
people,
vec![
Person::new("John".to_string(), 22, 6433.34),
Person::new("Zoe".to_string(), 25, 9483.54),
Person::new("Al".to_string(), 60, 2433.64),
]
);
// // 根据 salary 值对 people 进行排序(从大到小)
people.sort_by(|a, b| b.salary.partial_cmp(&a.salary).unwrap_or(Ordering::Equal));

assert_eq!(
people,
vec![
Person::new("Zoe".to_string(), 25, 9483.54),
Person::new("John".to_string(), 22, 6433.34),
Person::new("Al".to_string(), 60, 2433.64),
]
);
}