是Rust里面最常用的 日期和時間 庫了。不管什么情況下,都應(yīng)該使用這個庫,而不是其他的庫。
其中有一個很重要的特征是: 支持serde的序列化和反序列化. 當(dāng)然也用到了這個特性。需要開啟下。
chrono?=?{?version?=?"0.4.22",?features?=?["serde"]?}
下面說明幾個經(jīng)典的用法:
use?chrono::prelude::*;
///?獲取當(dāng)前時區(qū)?現(xiàn)在時間
///?2022-10-22?10:57:49.771598?+08:00
let?local:?DateTime?=?Local::now();
println!("{}",?local);
///?獲取當(dāng)前時間的時間戳
///?1666408311
println!("當(dāng)前時間戳:{}",?local.timestamp());
///?時間格式化
let?format?=?local.format("%Y-%m-%d?%H:%M");
assert_eq!(format!("{}",?format),?"2022-10-22?11:11");
///?字符串轉(zhuǎn)時間
let?dt?=?Local.datetime_from_str("2022-10-22?11:03:23",?"%Y-%m-%d?%H:%M:%S");
///?2022-10-22T11:03:23+08:00
println!("{:?}",?dt.unwrap())
clap
clap文檔[2]
Rust的命令行參數(shù)解析器.
非常強(qiáng)大數(shù)據(jù)庫中use的用法,不用自己手動解析程序的參數(shù).
使用方式如下:
先添加到依賴中
cargo?add?clap?--features?derive
use?clap::Parser;
#[derive(Parser,?Debug)]
#[command(author,?about,?long_about?=?None)]
#[command(name?=?"MyApp")]
#[command(version?=?"1.2.3")]
struct?Args?{
????#[arg(short,long)]
????name:?String,
????#[arg(short,long,default_value_t=1)]
????count:?u8,
}
fn?main()?{
????let?args?=?Args::parse();
????for?_?in?0..args.count?{
????????println!("Hello?{}!",?args.name)
????}
}
更多的用法可以參考clap用法[3]
fern
fern是Rust中的一個高效、可配置的日志庫。
fern [4]
看下怎么使用.
先添加依賴
[dependencies]
log?=?"0.4"
fern?=?"0.6"
這里可能要問,為什么還需要log庫呢, 因為Rust里面也是用門面模式來構(gòu)建日志的,就是標(biāo)準(zhǔn)庫不提供具體的實現(xiàn)。比如像Java里面的-,slf4j日志門面庫,當(dāng)然使用最多的是slf4j了,同樣在使用的時候數(shù)據(jù)庫中use的用法,你也需要一個具體的實現(xiàn)包,比如. 所以類比一下,Java中的slf4j就相當(dāng)于Rust里面的log, 而就是這里的fern.同樣的rust里面的log也只提供了一個單獨的日志API,它抽象了實際的日志實現(xiàn)。具體庫可以使用此lib提供的日志記錄API,而這些庫的使用者可以選擇最適合其用例的日志記錄的實現(xiàn)。
有了fern,所有記錄器配置都是通過結(jié)構(gòu)實例上的類構(gòu)建器方法完成的。下面是一個的配置示例,首先會格式化日志,并將所有Debug級別以上日志發(fā)送到和.log文件
///?setup_logger?按照想要的方式裝配日志格式
///?整個setup過程就是一個builder模式
///?`fern::Dispatch::new()`?會創(chuàng)建一個空的配置
///?`.format(|...| ...)`?添加格式化程序,修改所有發(fā)送的消息。
///?`chrono::Local::now()`?使用`chrono`庫獲取本地時區(qū)中的當(dāng)前時間
///?`.format("[%Y-%m-%d][%H:%M:%S]")`使用chrono的格式說明符將時間轉(zhuǎn)換為可讀字符串
///?`out.finish(format_args!(...))`?調(diào)用`fern::FormattingCallback`來提交格式化的消息。
///?`.apply()`?使用配置并將其實例化為當(dāng)前運(yùn)行時全局日志。?注意apply只能調(diào)用一次
fn?setup_logger()?->?Result<(),?fern::InitError>?{
????fern::Dispatch::new().format(|out,?message,?record|?{
????????out.finish(format_args!(
????????????"{}?[{}]?[{}]?{}",?chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
????????????record.target(),
????????????record.level(),
????????????message
????????))
????})
????????.level(log::LevelFilter::Debug)
????????.chain(std::io::stdout())
????????.chain(fern::log_file("output.log")?).apply()?;
????Ok(())
}
使用:
fn?main()?{
????setup_logger();
????info!("Hello,?碼小菜!");
????warn!("Warning!");
}
輸出如下:
[2022-10-22][17:17:29]?[test_r]?[INFO]?Hello,?碼小菜!
[2022-10-22][17:17:29]?[test_r]?[WARN]?Warning!
同時在當(dāng)前項目根目錄,也有日志文件.log
大家都清楚,就是Rust提供的異步編程的抽象。
這個庫為編寫異步代碼提供了許多核心抽象, 比如:
同時也包含了 I/O和cross-task 的抽象。
當(dāng)然了, 提供這一切的基礎(chǔ)能力是系統(tǒng)任務(wù),它是輕量級線程的一種形式。大型異步計算使用、和sink構(gòu)建,然后生成獨立的任務(wù),直到任務(wù)運(yùn)行到完成,但不會阻塞運(yùn)行它們的線程。
下面的示例描述了如何使用宏和關(guān)鍵字(如async和await!)構(gòu)建和使用任務(wù)系統(tǒng)上下文。
#[test]
fn?test_futures()?{
????///?注意這里需要在使用Futures庫的時候,開啟`features=["thread-pool"]`?特性
????use?futures::executor::ThreadPool;
????use?futures::executor;
????use?futures::channel::mpsc;
????///?首先需要一個運(yùn)行我們下面構(gòu)建的異步任務(wù)的線程池
????let?pool?=?ThreadPool::new().expect("Failed?to?build?pool");
????///?需要一個?異步任務(wù)通信的無界通道
????///?注意這里使用的是`futures::channel::mpsc`模塊,不是`std::sync::mpsc`
????///
????///?具體這里的區(qū)別在哪,后面會寫文章專門做對比
????///?https://docs.rs/futures/0.3.25/futures/channel/mpsc/index.html
????///
????///?用于跨異步任務(wù)發(fā)送消息的多生產(chǎn)者、單一使用者隊列
????let?(tx,?rx)?=?mpsc::unbounded::<i32>();
????///?通過async關(guān)鍵字構(gòu)建一個異步任務(wù)塊,?其實底層就是async在編譯期幫你`impl`了`Future`
????///?不過,這個時候還沒有提供運(yùn)行時,所以是不會運(yùn)行的
????let?fut_values?=?async?{
????????///?這里又構(gòu)建了一個異步任務(wù)塊,同樣的async生成了Future
????????///?因為這個異步任務(wù)在父級異步塊里面,?它將與父塊的執(zhí)行程序一起提供
????????let?fut_tx_result?=?async?move?{
????????????(0..100).for_each(|v|?{
????????????????tx.unbounded_send(v).expect("Failed?to?send");
????????????})
????????};
????????///?使用提供的線程池運(yùn)行生成的future
????????pool.spawn_ok(fut_tx_result);
????????///?將接受到的值映射為一個新值
????????///?因為Receiver實現(xiàn)Stream,并能夠從通道中讀取值。
????????///?而map是Stream?trait中的方法
????????///?這里不展開說,后面會讀下Stream的源碼
????????let?fut_values?=?rx.map(|v|?v*2).collect();
????????fut_values.await
????};
????let?values:?Vec<i32>?=?executor::block_on(fut_values);
????println!("Values={:?}",?values)
}
參考資料[1]
:
[2]
clap文檔:
[3]
clap用法:
[4]
fern: