RUST实践
密码
自定义密码
| use rand::Rng; |
| |
| pub fn main() { |
| const CHARSET: &[u8] = b"abcdefghijklmnopqrstuvwxyz\ |
| 0123456789)(*&^%$#@!~)"; |
| const PASSWORD_LEN: usize = 30; |
| 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); |
| } |
Vector排序
整数
| fn main() { |
| let mut vec = vec![1, 5, 8, 90, 89]; |
| println!("前: {:?}", vec); |
| |
| vec.sort(); |
| println!("后: {:?}", vec); |
| assert_eq!(vec, vec![1, 5, 8, 90, 89]); |
| } |
浮点数
| fn main() { |
| let mut vec = vec![1.8, 5.1, 8.9, 0.90, 8.9]; |
| println!("前: {:?}", vec); |
| |
| vec.sort_by(|a, b| a.partial_cmp(b).unwrap()); |
| println!("后: {:?}", vec); |
| } |
结构体
| #[derive(Debug, Eq, PartialEq, PartialOrd, Ord)] |
| struct Person { |
| name: String, |
| age: u32 |
| } |
| |
| impl Person { |
| pub fn new(name: &str, age: u32) -> Self { |
| Person { |
| name: name.to_string(), |
| age |
| } |
| } |
| } |
| |
| pub fn main() { |
| let mut peoples = vec![ |
| Person::new("Zhang", 25), |
| Person::new("Liu", 60), |
| Person::new("Wang", 18), |
| ]; |
| println!("前: {:?}", peoples); |
| peoples.sort_by(|a, b| b.age.cmp(&a.age)); |
| println!("后:{:?}", peoples); |
| } |
命令行参数
| use clap::{Arg, App}; |
| |
| pub fn main() { |
| let matches = App::new("测试程序") |
| .version("0.1.0") |
| .author("MUWUREN") |
| .about("Test clap") |
| .arg(Arg::with_name("file") |
| .short("f") |
| .long("file") |
| .takes_value(true) |
| .help("a cool file")) |
| .arg(Arg::with_name("num") |
| .short("n") |
| .long("num") |
| .takes_value(true) |
| .help("Five less than")) |
| .get_matches(); |
| |
| let myfile = matches.value_of("file").unwrap_or("input.txt"); |
| println!("file: {}", myfile); |
| |
| let num_str = matches.value_of("num"); |
| match num_str { |
| None => println!("No idea!"), |
| Some(s) => { |
| match s.parse::<i32>() { |
| Ok(n) => println!("NUM: {}", n), |
| Err(e) => println!("Error: '{}', {}", s, e), |
| } |
| } |
| } |
| } |
终端颜色
| use ansi_term::{Colour, Style}; |
| |
| pub fn main() { |
| |
| println!("This is {} in color, {} in color and {} in color", |
| Colour::Red.paint("red"), |
| Colour::Blue.bold().paint("blue"), |
| Colour::Green.bold().paint("green")); |
| |
| |
| println!("{} and this is not", Style::new().bold().paint("BOLD")); |
| } |
Tar
解压
| use std::fs::File; |
| use flate2::read::GzDecoder; |
| use tar::Archive; |
| |
| fn main() -> Result<(), std::io::Error> { |
| let path = "archive.tar.gz"; |
| |
| let tar_gz = File::open(path)?; |
| let tar = GzDecoder::new(tar_gz); |
| let mut archive = Archive::new(tar); |
| archive.unpack(".")?; |
| |
| Ok(()) |
| } |
压缩
| use std::fs::File; |
| use flate2::Compression; |
| use flate2::write::GzEncoder; |
| |
| pub fn main() -> Result<(), std::io::Error>{ |
| let tar_gz = File::create("ab.tar.gz")?; |
| let enc = GzEncoder::new(tar_gz, Compression::default()); |
| let mut tar = tar::Builder::new(enc); |
| tar.append_dir_all("logs/", "/tmp/ccls/")?; |
| Ok(()) |
| } |
线程
短期线程
| pub fn main() { |
| let arr = &[1, 25, 3, -4]; |
| let max = find_max(arr); |
| assert_eq!(max, Some(25)); |
| } |
| |
| fn find_max(arr: &[i32]) -> Option<i32> { |
| const THRESHOLD: usize = 2; |
| if arr.len() <= THRESHOLD { |
| return arr.iter().cloned().max(); |
| } |
| let mid = arr.len() / 2; |
| let (left, right) = arr.split_at(mid); |
| |
| crossbeam::scope(|s| { |
| let thread_l = s.spawn(|_| find_max(left)); |
| let thread_r = s.spawn(|_| find_max(right)); |
| |
| let max_l = thread_l.join().unwrap()?; |
| let max_r = thread_r.join().unwrap()?; |
| |
| Some(max_l.max(max_r)) |
| }).unwrap() |
| } |
管道
| extern crate crossbeam; |
| extern crate crossbeam_channel; |
| |
| use crossbeam_channel::bounded; |
| use std::thread; |
| use std::time::Duration; |
| |
| pub fn main() { |
| let (snd1, rcv1) = bounded(1); |
| let (snd2, rcv2) = bounded(1); |
| let n_msgs = 4; |
| let n_workers = 2; |
| |
| crossbeam::scope(|s| { |
| s.spawn(|_| { |
| for i in 0..n_msgs { |
| snd1.send(i).unwrap(); |
| println!("Source sent {}", i); |
| } |
| |
| drop(snd1); |
| }); |
| |
| for _ in 0..n_workers { |
| let (sendr, recvr) = (snd2.clone(), rcv1.clone()); |
| s.spawn(move |_| { |
| thread::sleep(Duration::from_secs(1)); |
| for msg in recvr.iter() { |
| println!("Worker {:?} received {}", thread::current().id(), msg); |
| sendr.send(msg * 2).unwrap(); |
| } |
| }); |
| } |
| drop(snd2); |
| |
| for msg in rcv2.iter() { |
| println!("Sink received {}", msg); |
| } |
| }).unwrap(); |
| } |
无限容量管道
| use std::{thread, time}; |
| use crossbeam_channel::unbounded; |
| |
| pub fn main() { |
| let (snd, rcv) = unbounded(); |
| let n_msgs = 5; |
| crossbeam::scope(|s| { |
| s.spawn(|_| { |
| for i in 0..n_msgs { |
| snd.send(i).unwrap(); |
| thread::sleep(time::Duration::from_secs(1)); |
| } |
| }); |
| }).unwrap(); |
| for _ in 0..n_msgs { |
| let msg = rcv.recv().unwrap(); |
| println!("{}", msg); |
| } |
| } |
全局变量
| use error_chain::error_chain; |
| use lazy_static::lazy_static; |
| use std::sync::Mutex; |
| |
| error_chain!{ } |
| |
| lazy_static! { |
| static ref FRUIT: Mutex<Vec<String>> = Mutex::new(Vec::new()); |
| } |
| |
| fn insert(fruit: &str) -> Result<()> { |
| let mut db = FRUIT.lock().map_err(|_| "Failed to acquire MutexGuard!")?; |
| db.push(fruit.to_string()); |
| Ok(()) |
| } |
| |
| pub fn main() -> Result<()> { |
| insert("apple")?; |
| insert("orange")?; |
| insert("peach")?; |
| { |
| let db = FRUIT.lock().map_err(|_| "Failed TO acquire MutexGuard")?; |
| db.iter().enumerate().for_each(|(i, item)| println!("{}: {}", i, item)); |
| } |
| insert("grape")?; |
| Ok(()) |
| } |
SHA计算
| use walkdir::WalkDir; |
| use std::fs::File; |
| use std::io::{BufReader, Read, Error}; |
| use threadpool::ThreadPool; |
| use std::path::Path; |
| use std::sync::mpsc::channel; |
| use ring::digest::{Context, Digest, SHA256}; |
| |
| fn is_iso(entry: &Path) -> bool { |
| match entry.extension() { |
| Some(e) if e.to_string_lossy().to_lowercase() == "iso" => true, |
| _ => false |
| } |
| } |
| |
| fn compute_digest<P: AsRef<Path>>(filepath: P) -> Result<(Digest, P), Error> { |
| let mut buf_reader = BufReader::new(File::open(&filepath)?); |
| let mut context = Context::new(&SHA256); |
| let mut buffer = [0; 1024]; |
| |
| loop { |
| let count = buf_reader.read(&mut buffer)?; |
| if count == 0 { |
| break; |
| } |
| context.update(&buffer[..count]); |
| } |
| Ok((context.finish(), filepath)) |
| } |
| |
| pub fn main() -> Result<(), Error> { |
| let pool = ThreadPool::new(num_cpus::get()); |
| |
| let (tx, rx) = channel(); |
| |
| for entry in WalkDir::new("/home/nsfoxer/ISO") |
| .follow_links(true) |
| .into_iter() |
| .filter_map(|e| e.ok()) |
| .filter(|e| !e.path().is_dir() && is_iso(e.path())) { |
| let path = entry.path().to_owned(); |
| let tx = tx.clone(); |
| pool.execute(move || { |
| let digest = compute_digest(path); |
| tx.send(digest).expect("Could not send data!"); |
| }); |
| } |
| drop(tx); |
| for t in rx.iter() { |
| let (sha, path) = t?; |
| println!("{:?}, {:?}", sha, path); |
| } |
| Ok(()) |
| } |
绘图
朱利亚集 f(n+1)=f(n)*f(n)+c
| use error_chain::error_chain; |
| use std::sync::mpsc::{channel, RecvError}; |
| use threadpool::ThreadPool; |
| use num::complex::Complex; |
| use image::{ImageBuffer, Pixel, Rgb}; |
| |
| error_chain! { |
| foreign_links { |
| MpscRecv(RecvError); |
| Io(std::io::Error); |
| } |
| } |
| |
| fn wavelength_to_rgb(wavelength: u32) -> Rgb<u8> { |
| let wave = wavelength as f32; |
| |
| let (r, g, b) = match wavelength { |
| 380..=439 => ((440.-wave)/(440.-380.), 0.0, 1.0), |
| 440..=489 => (0.0, (wave - 440.) / (490. - 440.), 1.0), |
| 490..=509 => (0.0, 1.0, (510. - wave) / (510. - 490.)), |
| 510..=579 => ((wave - 510.) / (580. - 510.), 1.0, 0.0), |
| 580..=644 => (1.0, (645. - wave) / (645. - 580.), 0.0), |
| 645..=780 => (1.0, 0.0, 0.0), |
| _ => (0.0, 0.0, 0.0), |
| }; |
| let factor = match wavelength { |
| 380..=419 => 0.3 + 0.7 * (wave - 380.) / (420. - 380.), |
| 701..=780 => 0.3 + 0.7 * (780. - wave) / (780. - 700.), |
| _ => 1.0, |
| }; |
| |
| let (r, g, b) = (normalize(r, factor), normalize(g, factor), normalize(b, factor)); |
| Rgb::from_channels(r, g, b, 0) |
| } |
| |
| fn julia(c: Complex<f32>, x: u32, y:u32, width: u32, height: u32, max_iter: u32) -> u32 { |
| let width = width as f32; |
| let height = height as f32; |
| |
| let mut z = Complex { |
| re: 3.0 * (x as f32 - 0.5*width) / width, |
| im: 2.0 * (y as f32 - 0.5*height) / height, |
| }; |
| |
| let mut i = 0; |
| for t in 0..max_iter { |
| if z.norm() >= 2.0 { |
| break; |
| } |
| z = z*z+c; |
| i = t; |
| } |
| i |
| } |
| |
| fn normalize(color: f32, factor: f32) -> u8 { |
| ((color * factor).powf(0.8) * 255.) as u8 |
| } |
| |
| pub fn main() -> Result<()> { |
| let (width, height) = (1920, 1080); |
| let mut img = ImageBuffer::new(width, height); |
| let iterations = 300; |
| |
| let c = Complex::new(-0.8, 0.156); |
| let pool = ThreadPool::new(num_cpus::get()); |
| let (tx, rx) = channel(); |
| |
| for y in 0..height { |
| let tx = tx.clone(); |
| pool.execute(move || for x in 0..width { |
| let i = julia(c, x, y, width, height, iterations); |
| let pixel = wavelength_to_rgb(380+i*400/iterations); |
| tx.send((x, y, pixel)).expect("Could not send data!"); |
| }); |
| } |
| |
| for _ in 0..(width*height) { |
| let (x, y, pixel) = rx.recv()?; |
| img.put_pixel(x, y, pixel); |
| } |
| let _ = img.save("output.png").unwrap(); |
| Ok(()) |
| } |
改变数组
| use rayon::prelude::*; |
| |
| fn main() { |
| let mut arr = [0, 7, 9, 11]; |
| arr.par_iter_mut().for_each(|p| *p -= 1); |
| println!("{:?}", arr); |
| } |
数组测试
| use rayon::prelude::*; |
| |
| pub fn main() { |
| let arr = vec![1, 7, 9, 11]; |
| |
| |
| |
| assert!(!arr.par_iter().any(|n| (*n % 2) == 0)); |
| assert!(arr.par_iter().all(|n| (*n % 2) != 0)); |
| |
| |
| assert_eq!(arr.par_iter().find_any(|&&x| x == 9), Some(&9)); |
| |
| } |
排序
| use rand::{Rng, thread_rng}; |
| use rand::distributions::Alphanumeric; |
| use rayon::prelude::*; |
| |
| pub fn main() { |
| let mut arr = vec![String::new(); 100]; |
| arr.par_iter_mut().for_each(|p| { |
| let mut rng = thread_rng(); |
| *p = (0..50).map(|_| rng.sample(&Alphanumeric)).map(char::from).collect() |
| }); |
| arr.par_sort_unstable(); |
| println!("{:?}", arr); |
| |
| } |
Map-Reduce
| use rayon::prelude::*; |
| |
| struct Person { |
| age: u32, |
| } |
| |
| pub fn main() { |
| let v: Vec<Person> = vec![ |
| Person { age: 23 }, |
| Person { age: 19 }, |
| Person { age: 42 }, |
| Person { age: 17 }, |
| Person { age: 17 }, |
| Person { age: 31 }, |
| Person { age: 30 }, |
| ]; |
| |
| let num_over_30 = v.par_iter().filter(|&x| x.age > 30).count() as f32; |
| let sum_over_30 = v |
| .par_iter() |
| .map(|x| x.age) |
| .filter(|&x| x > 30) |
| .reduce(|| 0, |x, y| x + y); |
| let alt_sum_30: u32 = v.par_iter().map(|x| x.age).filter(|&x| x > 30).sum(); |
| let avg_over_30 = sum_over_30 as f32 / num_over_30; |
| let alt_avg_over_30 = alt_sum_30 as f32 / num_over_30; |
| |
| assert!((avg_over_30 - alt_avg_over_30).abs() < std::f32::EPSILON); |
| println!("The average age of people older than 30 is {}", avg_over_30); |
| } |
缩略图
| use error_chain::error_chain; |
| |
| use std::path::Path; |
| use std::fs::create_dir_all; |
| |
| use error_chain::ChainedError; |
| use glob::{glob_with, MatchOptions}; |
| use image::{ImageError, imageops::FilterType}; |
| use rayon::prelude::*; |
| |
| error_chain! { |
| foreign_links { |
| Image(ImageError); |
| Io(std::io::Error); |
| Glob(glob::PatternError); |
| } |
| } |
| |
| pub fn main() -> Result<()>{ |
| let options: MatchOptions = Default::default(); |
| let files: Vec<_> = glob_with("*.jpg", options)? |
| .filter_map(|x| x.ok()) |
| .collect(); |
| |
| if files.len() == 0 { |
| error_chain::bail!("No .jpg was founded!"); |
| } |
| |
| let thumb_dir = "thumbnails"; |
| create_dir_all(thumb_dir)?; |
| println!("Save {} thumbnails into `{}`...", files.len(), thumb_dir); |
| |
| let image_failures: Vec<_> = files |
| .par_iter() |
| .map(|path|{ |
| make_thumbnail(path, thumb_dir, 300) |
| .map_err(|e| e.chain_err(|| path.display().to_string())) |
| }) |
| .filter_map(|x| x.err()) |
| .collect(); |
| image_failures.iter().for_each(|x| println!("{}", x.display_chain())); |
| |
| println!("{} thumbnails saved successfully", files.len() - image_failures.len()); |
| Ok(()) |
| } |
| |
| fn make_thumbnail<PA, PB>(original: PA, thumb_dir: PB, longest_edge: u32) -> Result<()> |
| where |
| PA: AsRef<Path>, |
| PB: AsRef<Path>, |
| { |
| let img = image::open(original.as_ref())?; |
| let file_path = thumb_dir.as_ref().join(original); |
| |
| Ok(img.resize(longest_edge, longest_edge, FilterType::Nearest) |
| .save(file_path)?) |
| } |
密码
SHA256
| use error_chain::error_chain; |
| use data_encoding::HEXUPPER; |
| use ring::digest::{Context, Digest, SHA256}; |
| use std::fs::File; |
| use std::io::{BufReader, Read, Write}; |
| |
| error_chain! { |
| foreign_links { |
| Io(std::io::Error); |
| Decode(data_encoding::DecodeError); |
| } |
| } |
| |
| fn sha256_digest<R: Read>(mut reader: R) -> Result<Digest> { |
| let mut context = Context::new(&SHA256); |
| let mut buffer = [0; 1024]; |
| |
| loop { |
| let count = reader.read(&mut buffer)?; |
| if count == 0 { |
| break; |
| } |
| context.update(&buffer[..count]); |
| } |
| Ok(context.finish()) |
| } |
| |
| pub fn main() -> Result<()>{ |
| let path = "file.txt"; |
| |
| let mut output = File::create(path)?; |
| write!(output, "We will generate a digest of the text")?; |
| |
| let input = File::open(path)?; |
| let reader = BufReader::new(input); |
| let digest = sha256_digest(reader)?; |
| |
| println!("SHA-256 digest is {}", HEXUPPER.encode(digest.as_ref())); |
| Ok(()) |
| } |
HMAC签名和校验
| use ring::{hmac, rand}; |
| use ring::rand::SecureRandom; |
| use ring::error::Unspecified; |
| |
| pub fn main() -> Result<(), Unspecified> { |
| let mut key_value = [0u8; 48]; |
| let rng = rand::SystemRandom::new(); |
| rng.fill(&mut key_value)?; |
| let key = hmac::Key::new(hmac::HMAC_SHA256, &key_value); |
| |
| let message = "Legitimate and import message"; |
| println!("{}", &message); |
| |
| let signature = hmac::sign(&key, message.as_bytes()); |
| println!("{:?}", &signature); |
| |
| hmac::verify(&key, message.as_bytes(), signature.as_ref())?; |
| |
| Ok(()) |
| } |
密码salt和hash
| use data_encoding::HEXUPPER; |
| use ring::rand::SecureRandom; |
| use ring::{digest, pbkdf2, rand}; |
| use ring::error::Unspecified; |
| use std::num::NonZeroU32; |
| |
| pub fn main() -> Result<(), Unspecified> { |
| const CREDENTIAL_LEN: usize = digest::SHA512_OUTPUT_LEN; |
| let n_iter = NonZeroU32::new(100_000).unwrap(); |
| let rng = rand::SystemRandom::new(); |
| |
| let mut salt = [0u8; CREDENTIAL_LEN]; |
| rng.fill(&mut salt)?; |
| |
| let password = "Guess Me If You Can"; |
| let mut pbkdf2_hash = [0u8; CREDENTIAL_LEN]; |
| pbkdf2::derive( |
| pbkdf2::PBKDF2_HMAC_SHA512, |
| n_iter, |
| &salt, |
| &password.as_bytes(), |
| &mut pbkdf2_hash |
| ); |
| println!("Salt: {:?}", &salt); |
| println!("Salt: {}", HEXUPPER.encode(&salt)); |
| |
| println!("PBKDF2 hash: {:?}", &pbkdf2_hash); |
| println!("PBKDF2 hash: {}", HEXUPPER.encode(&pbkdf2_hash)); |
| |
| let should_succeed = pbkdf2::verify( |
| pbkdf2::PBKDF2_HMAC_SHA512, |
| n_iter, |
| &salt, |
| password.as_bytes(), |
| &pbkdf2_hash, |
| ); |
| let wrong_password = "Wrong Password"; |
| let should_fail = pbkdf2::verify( |
| pbkdf2::PBKDF2_HMAC_SHA512, |
| n_iter, |
| &salt, |
| wrong_password.as_bytes(), |
| &pbkdf2_hash, |
| ); |
| |
| assert!(should_succeed.is_ok()); |
| assert!(!should_fail.is_ok()); |
| Ok(()) |
| |
| } |
数据库
创建
| use rusqlite::{Connection, Result}; |
| |
| pub fn main() -> Result<()> { |
| let conn = Connection::open("cat.db")?; |
| |
| conn.execute( |
| "create table if not exists cat_colors( |
| id integer primary key, |
| name text not null unique |
| )", |
| [] |
| )?; |
| conn.execute( |
| "create table if not exists cats ( |
| id integer primary key, |
| name text not null, |
| color_id integer not null references cat_colors(id) |
| )", |
| [] |
| )?; |
| Ok(()) |
| } |
插入数据 事务
| use rusqlite::{Connection, Result}; |
| |
| pub fn main() -> Result<()> { |
| let mut conn = Connection::open("cat.db")?; |
| successful_tx(&mut conn)?; |
| |
| let res = rolled_back_tx(&mut conn); |
| assert!(res.is_err()); |
| |
| Ok(()) |
| } |
| |
| fn successful_tx(conn: &mut Connection) -> Result<()> { |
| let tx = conn.transaction()?; |
| |
| tx.execute("delete from cat_colors", [])?; |
| tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?; |
| tx.execute("insert into cat_colors (name) values (?1)", &[&"blue"])?; |
| |
| tx.commit() |
| } |
| |
| fn rolled_back_tx(conn: &mut Connection) -> Result<()> { |
| let tx = conn.transaction()?; |
| |
| tx.execute("delete from cat_colors", [])?; |
| tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?; |
| tx.execute("insert into cat_colors (name) values (?1)", &[&"lavender"])?; |
| |
| tx.commit() |
| } |
时间
测量运行时间
| use std::time::{Duration, Instant}; |
| use std::thread; |
| |
| pub fn main() { |
| let start = Instant::now(); |
| expensive_fun(); |
| let duration = start.elapsed(); |
| println!("消耗时间: {:?}", duration); |
| } |
| |
| fn expensive_fun() { |
| thread::sleep(Duration::from_secs(1)); |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)