【一起学Rust · 项目实战】使用getargs库来获取命令行参数

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

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还支持更多特性,比如子命令什么的,如果你感兴趣,可以看看官方提供的几个示例

相关推荐
伊玛目的门徒4 分钟前
HTTP SSE 流式响应处理:调用腾讯 智能应用开发平台ADP智能体的 API
python·网络协议·http·腾讯智能体·adp·智能应用开发平台
倔强的小石头_7 分钟前
Python 从入门到实战(八):类(面向对象的 “对象模板”)
服务器·开发语言·python
Mr_Xuhhh24 分钟前
第一部分:类和对象(中)— 取地址运算符重载
java·开发语言
Selegant27 分钟前
告别传统部署:用 GraalVM Native Image 构建秒级启动的 Java 微服务
java·开发语言·微服务·云原生·架构
qq_2147826139 分钟前
GWalkR,部分替代Tableau!
ide·python·jupyter
Liii40343 分钟前
Java集合详细讲解
java·开发语言
Yuner20001 小时前
Python机器学习:从零基础到深度实战
人工智能·python·机器学习
落羽的落羽1 小时前
【C++】哈希扩展——位图和布隆过滤器的介绍与实现
linux·服务器·开发语言·c++·人工智能·算法·机器学习
fish_xk1 小时前
类和对象(二)
开发语言·c++·算法
r i c k1 小时前
办公小程序开发----提高工作效率
python·python程序开发