• RUST实践.md


    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]); // failed
    }
    

    浮点数

    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() {
        // color
        println!("This is {} in color, {} in color and {} in color",
                 Colour::Red.paint("red"),
                 Colour::Blue.bold().paint("blue"),
                 Colour::Green.bold().paint("green")); // color and bold
    
        // Bold
        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);
                }
                // close channel
                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,  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];
    
        // any() --> 只要有一个
        // all() --> 全部都要
        assert!(!arr.par_iter().any(|n| (*n % 2) == 0));
        assert!(arr.par_iter().all(|n| (*n % 2) != 0));
    
        // 查找到第一个元素就返回,但不一定是vec的第一个元素
        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));
    }
    
  • 相关阅读:
    P5468 [NOI2019]回家路线
    P1919 【模板】A*B Problem升级版(FFT快速傅里叶)
    P4390 [BOI2007]Mokia 摩基亚
    P4234 最小差值生成树
    P5459 [BJOI2016]回转寿司
    P2173 [ZJOI2012]网络
    P2163 [SHOI2007]园丁的烦恼
    P3826 [NOI2017]蔬菜
    P3327 [SDOI2015]约数个数和
    P1829 [国家集训队]Crash的数字表格 / JZPTAB
  • 原文地址:https://www.cnblogs.com/nsfoxer/p/15532966.html
Copyright © 2020-2023  润新知