1 个不稳定版本
0.1.0 | 2021年7月22日 |
---|
#756 在 命令行界面
52KB
813 行
Lexopt
Lexopt 是一个 Rust 的参数解析器。它试图采用最简单的设计,同时确保正确性。它的简单性使得使用起来略显繁琐。
Lexopt 的特点:
- 小巧:单个文件,无依赖,无宏。易于审计或商业化。
- 正确:支持标准约定,避免歧义。经过测试和模糊测试。
- 严格:参数作为
OsString
返回,强制您显式转换。这可以让您处理坏编码的文件名。 - 命令式:选项按找到的顺序返回,无需预先声明。
- 简约:仅提供最基本的功能。
- 不友好:没有帮助生成,错误消息经常缺乏上下文。
示例
struct Args {
thing: String,
number: u32,
shout: bool,
}
fn parse_args() -> Result<Args, lexopt::Error> {
use lexopt::prelude::*;
let mut thing = None;
let mut number = 1;
let mut shout = false;
let mut parser = lexopt::Parser::from_env();
while let Some(arg) = parser.next()? {
match arg {
Short('n') | Long("number") => {
number = parser.value()?.parse()?;
}
Long("shout") => {
shout = true;
}
Value(val) if thing.is_none() => {
thing = Some(val.into_string()?);
}
Long("help") => {
println!("Usage: hello [-n|--number=NUM] [--shout] THING");
std::process::exit(0);
}
_ => return Err(arg.unexpected()),
}
}
Ok(Args {
thing: thing.ok_or("missing argument THING")?,
number,
shout,
})
}
fn main() -> Result<(), lexopt::Error> {
let args = parse_args()?;
let mut message = format!("Hello {}", args.thing);
if args.shout {
message = message.to_uppercase();
}
for _ in 0..args.number {
println!("{}", message);
}
Ok(())
}
让我们一步步来看
- 我们使用
Parser::from_env()
开始解析。 - 我们循环调用
parser.next()
以获取所有参数,直到它们用完。 - 我们对参数进行匹配。
Short
和Long
指示一个选项。 - 要获取属于选项的值(如
10
在-n 10
中)我们调用parser.value()
。- 这返回一个标准的
OsString
。 - 为了方便,使用
use lexopt::prelude::*
会添加一个类似于str::parse
的.parse()
方法。
- 这返回一个标准的
Value
表示一个独立的参数。在这种情况下,是一个文件名。if thing.is_none()
是处理位置参数的一个有用模式。如果我们已经找到了thing
,我们将它传递给另一个情况。- 它还包含一个
OsString
。- 标准的
.into_string()
方法可以将其解码为普通的String
。
- 标准的
- 如果我们不知道如何处理一个参数,我们使用
return Err(arg.unexpected())
将其转换为错误消息。 - 字符串可以提升为错误以生成自定义错误消息。
这几乎涵盖了库中的所有功能。Lexopt为您做的事情很少。
有关带有有用模式的较大示例,请参阅examples/cargo.rs
。
命令行语法
支持以下约定
- 短选项(
-q
) - 长选项(
--verbose
) --
用于标记选项的结束=
用于将长选项与值分开(--option=value
)- 空格用于将选项与值分开(
--option value
,-f value
) - 未分隔的短选项(
-fvalue
) - 组合短选项(
-abc
表示-a -b -c
)
以下不支持
- 短选项的
-f=value
- 具有可选参数的选项(如GNU sed的
-i
,它可以用作独立的或作为-iSUFFIX
) - 单破折号长选项(如find的
-name
) - 缩写长选项(GNU的getopt允许您在可以无歧义地展开的情况下使用
--num
代替--number
)
Unicode
此库支持Unicode,同时容忍非Unicode参数。
短选项可以是Unicode,但只能是一个代码点。(如果您需要整个图形簇,可以使用长选项。如果您需要规范化,您自己处理,但这可以做到。)
选项可以与非Unicode参数组合。也就是说,--option=���
不会导致错误或破坏值。这非常难以支持:请参阅os_str_bytes
。
选项本身如果不合法Unicode,会被补丁为 String::from_utf8_lossy
。这意味着你之后可能会因为无法识别而引发错误。
为什么?
为了特定的应用,我在寻找一个小型且严格正确的解析器。虽然有一些紧凑的参数解析库,但我没有找到能够处理OsString
并且忠实实现参数语法所有复杂细节的库。
如果需要大量控制,例如精确的参数顺序很重要或不是所有选项都提前知道,这个库可能也很有用。它更像是词法分析器而不是解析器。
为什么不呢?
如果你不关心以下情况,则可能不值得使用此库:
- 你不在乎非Unicode参数
- 你不在乎精确的兼容性和正确性
- 你不在乎代码大小
- 你关心出色的错误消息
- 你讨厌样板代码
另请参阅
clap
/structopt
:功能非常全面。我所知道的唯一一个真正正确处理无效Unicode的Rust参数解析器,如果使用得当。体积较大。argh
和gumdrop
:更加轻量级,但仍然方便,足够强大,足以满足大多数需求。在无效Unicode上引发恐慌。argh
遵循 Fuchsia规范,因此不支持--option=value
和-ovalue
,只支持--option value
和-o value
。
pico-args
:比lexopt稍小,更容易使用(但不太严格)。ap
:我没有使用过它,但它似乎支持迭代解析,同时比lexopt更简单。- libc的
getopt
。
pico-args有一个有趣的表格,列出了不同解析器的构建时间和代码大小。我已经重新运行了测试,并添加了lexopt(使用examples/pico_test_app.rs
中的程序)
null | lexopt | pico-args | clap | gumdrop | structopt | argh | |
---|---|---|---|---|---|---|---|
二进制开销 | 0KiB | 14.5KiB | 13.5KiB | 372.8KiB | 17.7KiB | 371.2KiB | 16.8KiB |
构建时间 | 0.9s | 1.7s | 1.6s | 13.0s | 7.5s | 17.0s | 7.5s |
依赖项数量 | 0 | 0 | 0 | 8 | 4 | 19 | 6 |
测试版本 | - | 0.1.0 | 0.4.2 | 2.33.3 | 0.8.0 | 0.3.22 | 0.1.4 |
(测试在x86_64 Linux上使用Rust 1.53和cargo-bloat 0.10.1进行。)