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

相关推荐
沐知全栈开发3 小时前
HTML 颜色名
开发语言
property-4 小时前
C++中#define和const的区别
开发语言·c++
mit6.8244 小时前
[Agent开发平台] 后端的后端 | MySQL | Redis | RQ | idgen | ObjectStorage
人工智能·python
学编程的小虎4 小时前
用 Python + Vue3 打造超炫酷音乐播放器:网易云歌单爬取 + Three.js 波形可视化
开发语言·javascript·python
€8114 小时前
Java入门级教程23——配置Nginx服务器、轻量级HTTP服务开发、前后端分离实现完整应用系统
java·开发语言·仓颉·生成验证码
yunson_Liu4 小时前
编写Python脚本在域名过期10天内将域名信息发送到钉钉
开发语言·python·钉钉
星秀日4 小时前
框架--SpringMVC
java·开发语言·servlet
布林模型5 小时前
缠论工具czsc快速使用入门(二)
python·缠论·快速入门·czsc
邂逅you5 小时前
用python操作mysql之pymysql库基本操作
数据库·python·mysql