Rust中应该尝试使用的12个杀手级库

in rust •  4 years ago  (edited)

Rust中应该尝试使用的12个杀手级库

1、clap

clap在写一些CLI工具时非常有用,在ripgrep和Rust自己的Cargo都在使用,clap编译后非常小,而且加载启动非常快。clap会帮你处理命令行参数,可以自定义友好提示,支持函数式操作,非常方便

官网地址

use clap::App; 

fn main() { 
    App::new("myapp")
       .version("1.0")
       .about("Does great things!")
       .author("Kevin K.")
       .get_matches(); 
}

$ myapp --help
myapp 1.0 
Kevin K. 
Does great things! 

USAGE: 
    myapp [FLAGS] 

FLAGS: 
    -h, --help Prints this message 
    -V, --version Prints version information

2、serde

calp一样,serde是一个功能丰富且性能非常好的通用序列化库。

生产中不建议自己造轮子读写文件,你可以先定义你要的数据类型,然后使用serde库加载读写文件。另外serde库可以帮你完成YAML,JSON的序列化和反序化,非常的方便

官网

use serde::{Serialize, Deserialize};

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

fn main() {
    let point = Point { x: 1, y: 2 };

    // Convert the Point to a JSON string.
    let serialized = serde_json::to_string(&point).unwrap();

    // Prints serialized = {"x":1,"y":2}
    println!("serialized = {}", serialized);

    // Convert the JSON string back to a Point.
    let deserialized: Point = serde_json::from_str(&serialized).unwrap();

    // Prints deserialized = Point { x: 1, y: 2 }
    println!("deserialized = {:?}", deserialized);
}

3、reqwest

reqwestrequest一样,是一个http协议的客户端库,帮大多数人做了一些希望HTTP客户端为他们做的许多事情,发请求,超时处理,多种格式支持,异步同步请求,代理等等

地址

// This will POST a body of `{"lang":"rust","body":"json"}`
let mut map = HashMap::new();
map.insert("lang", "rust");
map.insert("body", "json");

let client = reqwest::Client::new();
let res = client.post("http://httpbin.org/post")
    .json(&map)
    .send()
    .await?;

4、rayon

rayon是一个可以并行提供数据的库,它知道如何合理的拆分数据块并合理的使用cpu。比如你想在一个列表上并行使用map时就可以使用它。这就有意思了,在写一些CLI工具的时候很有用,并不是所有的编程语言都可以在命令行并行跑一些数据

github

use rayon::prelude::*;
fn sum_of_squares(input: &[i32]) -> i32 {
    input.par_iter() // <-- just change that!
         .map(|&i| i * i)
         .sum()
}

5、slog and log

slog是Rust中非常完整的一个日志库。很多有名的库也使用它来做日志库,比如 term,json等等。但是log库正在成为Rust标准库的一部分,可以考虑切换到log库上

slog github

let decorator = slog_term::PlainSyncDecorator::new(std::io::stdout());
    let drain = slog_term::FullFormat::new(decorator).build().fuse();

    let root_log = slog::Logger::root(drain, o!("version" => "0.5"));
    let server_log = root_log.new(o!("host" => "localhost", "port" => "8080"));
    let peer1_log =
        server_log.new(o!("peer_addr" => "8.8.8.8", "port" => "18230"));
    let peer2_log =
        server_log.new(o!("peer_addr" => "82.9.9.9", "port" => "42381"));

    info!(server_log, "starting");
    info!(server_log, "listening");
    debug!(peer2_log, "connected");
    debug!(peer2_log, "message received"; "length" => 2);
    debug!(peer1_log, "connected");
    debug!(peer2_log, "response sent"; "length" => 8);
    debug!(peer2_log, "disconnected");
    debug!(peer1_log, "message received"; "length" => 2);
    debug!(peer1_log, "response sent"; "length" => 8);
    debug!(peer1_log, "disconnected");
    info!(server_log, "exit");

6、itertools

写代码的时候,在List上加N多个操作符非常的繁琐,幸好有itertools帮我们处理,方便的很,比如你要对一个list做map完后排序,排序完后分组,你要怎么做?

github

 // using Itertools::fold_results to create the result of parsing
    let irises = DATA.lines()
                     .map(str::parse)
                     .fold_ok(Vec::new(), |mut v, iris: Iris| {
                         v.push(iris);
                         v
                     });
    let mut irises = match irises {
        Err(e) => {
            println!("Error parsing: {:?}", e);
            std::process::exit(1);
        }
        Ok(data) => data,
    };

    // Sort them and group them
    irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name));

7、hyper

hyper是一个用Rust编写的快速HTTP实现(与用C编写的相反,C编写的涵盖了动态语言的性能)。 你会发现hyper几乎存在于您使用的每个高级库中,如果直接使用它,感觉有点像NettyFinagle

官网地址: https://hyper.rs/

use std::{convert::Infallible, net::SocketAddr};
use hyper::{Body, Request, Response, Server};
use hyper::service::{make_service_fn, service_fn};

async fn handle(_: Request<Body>) -> Result<Response<Body>, Infallible> {
    Ok(Response::new("Hello, World!".into()))
}

#[tokio::main]
async fn main() {
    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));

    let make_svc = make_service_fn(|_conn| async {
        Ok::<_, Infallible>(service_fn(handle))
    });

    let server = Server::bind(&addr).serve(make_svc);

    if let Err(e) = server.await {
        eprintln!("server error: {}", e);
    }
}

8、Actix

不用hyper还能用什么? 当然是Actix了, 使用Actix会变得非常简单。一般来说也经常使用Actix而不是Hyper吧,因为Actix更高级,并且在构建服务上更成熟。 构建web可以直接在Hyper上使用Actix,除非你需要构建一些靠近协议层硬件层的服务,或者要写一个基于Hyper的库。

github: https://github.com/actix/actix-web

use actix_web::{get, web, App, HttpServer, Responder};

#[get("/{id}/{name}/index.html")]
async fn index(web::Path((id, name)): web::Path<(u32, String)>) -> impl Responder {
    format!("Hello {}! id:{}", name, id)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| App::new().service(index))
        .bind("127.0.0.1:8080")?
        .run()
        .await
}

9、PyO3

Python的Rust绑定。 包括运行Rust二进制文件中的Python代码并与之交互,以及编写本机Python模块。

可能你还不信,但是你可以看看hyperjson,一种由Rust的serde(之前文章介绍过) 支持的PythonJSON库,github地址:https://github.com/mre/hyperjson

依靠Rust的安全性和serde的性能,几乎可以毫不费力地获得一个安全的并且是Python写的最快的JSON库之一,不得不服啊

那你怎么把它用到自己平时写bug上呢:总结三步:

1、找到一个好的Rust库

2、用PyO3包一下

3、开始体验速度

use pyo3::prelude::*;
use pyo3::wrap_pyfunction;

/// Formats the sum of two numbers as string.
#[pyfunction]
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
    Ok((a + b).to_string())
}

/// A Python module implemented in Rust.
#[pymodule]
fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;

    Ok(())
}

10、proptest

proptest是一个非常好用的测试库,类似python里面的[Hypothesis](http://hypothesis.works/),妈妈再也不用担心我写单元测试了。

地址: https://lib.rs/crates/proptest

fn parse_date(s: &str) -> Option<(u32, u32, u32)> {
    if 10 != s.len() { return None; }
    if "-" != &s[4..5] || "-" != &s[7..8] { return None; }

    let year = &s[0..4];
    let month = &s[6..7];
    let day = &s[8..10];

    year.parse::<u32>().ok().and_then(
        |y| month.parse::<u32>().ok().and_then(
            |m| day.parse::<u32>().ok().map(
                |d| (y, m, d))))
}

11、libloading

如果你想将Go或任何其他c-lib库混入Rust中来,libloading可能会非常合适。

首先必须承认的一个问题就是,Rust现在的生态和积累了数10年,20年的c/c++来说还相对较弱,要接受Rust生态中某些部分还没有准备就绪,而且要勇敢的善于使用别的语言库来完成你要使用Rust开发项目这样一项工作,这时候你用libloading就行了,会帮你绑定到Rust中的,如果你放弃了因为生态问题,那你就可能永远入不了坑了。

地址: https://docs.rs/libloading/0.5.0/libloading/

extern crate libloading as lib;

fn call_dynamic() -> lib::Result<u32> {
    let lib = lib::Library::new("/path/to/liblibrary.so")?;
    unsafe {
        let func: lib::Symbol<unsafe extern fn() -> u32> = lib.get(b"my_func")?;
        Ok(func())
    }
}

这就是Rust中现阶段比较方便实用的12个库,Rust一直在发展,一直在包容并进,我们能做的就是使用它,多发现问题,多造轮子,多写一些没用的bug。

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!