
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、getargs的特性
-
- [1. 支持的选项](#1. 支持的选项)
- [2. 优点](#2. 优点)
- [3. 性能](#3. 性能)
- 二、基本概念
- 三、安装与使用
- 总结
前言
getargs是一种底层、高效且通用的参数解析器,其工作方式类似于getopts. 它通过生成选项流来工作,在每个选项之后,你的代码决定是否需要和检索选项的值。
不需要预先声明有效选项列表,因此 getargs不必为它们分配空间或花费运行时搜索它们。这也意味着你必须编写自己的帮助消息,但由于--help只是另一个参数标志,因此对您的操作没有任何限制。
初次以外,经过大量测试,该库在使用和性能上都取得了较好的成绩,是命令行参数解析库里面最值得学习的一个库。
一、getargs的特性
1. 支持的选项
- 短标志
-f
和长标志--flag
- 带参数
-f value
和--flag value
- 必填参数
-fvalue
和--flag=value
- 位置参数和
--
- 参数任意顺序
2. 优点
- 零成本
- 零拷贝
- 零不安全代码
- 零依赖
- 零分配
- 使用简单但用途广泛
- 兼容#![no_std]
- 兼容&str和&[u8]
3. 性能
getargs在分析和优化方面投入了大量精力,在现代机器上,解析一个包含 12 个参数的短数组需要不到 0.2μs
的时间。
在测试中,getargs它比 crates.io 上的所有其他参数解析库都要快。它最接近的竞争对手是gumdrop,在最坏的情况下只慢了约 30%,而它第二接近的竞争对手是getopt,它需要三倍的时间。其他库降级很快;clap需要 45 倍的时间。(虽然这不是一个完全公平的比较,因为clap它不仅仅是一个参数解析库,而是一个完整的命令行应用程序框架。对于简单的任务,它可能过于合格。)
二、基本概念
Options
是库的主要导出,并处理参数解析。Argument
为每种可以解析的类型实现 Options,例如&str和&[u8]。Opt
表示一个短选项或长选项,由Options::next_opt返回 。Arg
表示由Options::next_arg返回的选项或位置参数。Error
表示解析错误。
三、安装与使用
1.安装依赖
在Cargo.toml
文件中添加依赖
getargs = "0.5.0"
添加好后如下图所示
2.获取Options
首先引入标准库的args库
rust
use std::env::args;
然后获取应用程序的参数,并且存到一个vector里面(Windows操作系统
)
rust
let args = std::env::args()
.skip(1) // 直接跳过第一个参数(应用程序自己的名字)
.collect::<Vec<_>>();
如果是Linux
系统,你使用以下代码获取应用程序的参数
rust
let args = argv::iter().skip(1).map(OsStrExt::as_bytes);
注意
:argv随时可能会内存泄露
然后,将vector传递给Options::new
:
rust
let mut opts = Options::new(args);
3.解析Options
首先确定,你的程序调用方式像下面这样
usage: command [OPTIONS] [ARGS]...
通过死循环判断Options::next_opt
是否还有参数,代码如下
rust
let mut opts = Options::new(opts);
while let Some(opt) = opts.next_opt()? {
// 这里写你的解析代码
}
你也可以获取位置参数
rust
for positional in opts.positionals() {
// 解析代码
}
下面是官方提供的解析命令行例子
rust
use getargs::{Opt, Options};
use std::env::args;
fn main() {
let mut args = args().skip(1).collect::<Vec<_>>();
if args.is_empty() {
args.push(String::from("--help")); // help the user out :)
}
let mut opts = Options::new(args.iter().map(String::as_str));
while let Some(opt) = opts.next_opt().expect("argument parsing error") {
match opt {
Opt::Short('h') | Opt::Long("help") => {
eprintln!(
r"Usage: print.rs [OPTIONS] [ARGS]...
这个示例输出传递给它的所有选项和位置参数。
它还包括一些短的和长的选项,它们有一个必需的或可选值。
-h, --help 显示此帮助并退出
-o, --optional 使用一个可选值并输出结果
-r, --required 使用所需的值并输出它
<其他> 输出通过的标志"
);
return;
}
Opt::Short('o') | Opt::Long("optional") => {
eprintln!("option {:?}: {:?}", opt, opts.value_opt());
}
Opt::Short('r') | Opt::Long("required") => {
eprintln!("option {:?}: {:?}", opt, opts.value());
}
_ => eprintln!("option: {:?}", opt),
}
}
for arg in opts.positionals() {
eprintln!("positional: {:?}", arg)
}
}
4.不按顺序解析Options
现在的命令行程序都不是特别要求参数位置是否固定死了,这表示变得更加智能了。就比如说连接数据库
mysql -uroot -p123456 -hlocalhost -P3306
也可以这么写
mysql -uroot -hlocalhost -P3306 -p123456
它的参数位置是随意的。
要想实现这个效果,在getargs里面非常简单,只需要将上面的next_opt
改成next_arg
即可,不需要做其他改动
rust
let mut opts = Options::new(args);
while let Some(arg) = opts.next_arg()? {
// ...
match arg {
Arg::Short('h') | Arg::Long("help") => { /* ... */ }
Arg::Short('v') | Arg::Long("version") => { /* ... */ }
Arg::Positional(positional) => { /* ... */ }
_ => panic!("未知选项: {}", arg)
}
}
以下是官方提供的完整实例
rust
use getargs::{Arg, Options};
use std::env::args;
fn main() {
let mut args = args().skip(1).collect::<Vec<_>>();
if args.is_empty() {
args.push(String::from("--help")); // help the user out :)
}
let mut opts = Options::new(args.iter().map(String::as_str));
while let Some(arg) = opts.next_arg().expect("argument parsing error") {
match arg {
Arg::Short('h') | Arg::Long("help") => {
eprintln!(
r"Usage: print.rs [OPTIONS] [ARGS]...
这个示例输出传递给它的所有选项和位置参数。
它还包括一些短的和长的选项,它们有一个必需的或可选值。
-h, --help 显示此帮助并退出
-o, --optional 使用一个可选值并输出结果
-r, --required 使用所需的值并输出它
<其他> 输出通过的标志"
);
return;
}
Arg::Short('o') | Arg::Long("optional") => {
eprintln!("option {:?}: {:?}", arg, opts.value_opt());
}
Arg::Short('r') | Arg::Long("required") => {
eprintln!("option {:?}: {:?}", arg, opts.value());
}
Arg::Short(_) | Arg::Long(_) => eprintln!("option: {:?}", arg),
Arg::Positional(arg) => eprintln!("positional: {:?}", arg),
}
}
}
总结
getargs还支持更多特性,比如子命令什么的,如果你感兴趣,可以看看官方提供的几个示例。