3 个版本

0.0.2 2020年2月25日
0.0.1 2020年2月25日
0.0.0 2020年2月7日

#170 in #subcommand

MIT/Apache

3KB
60 代码行数(不含注释)

Argh 演示

真正的知识来源于实践。

最近,我注意到一个名为 "argh" 的命令行参数解析工具,它轻量级、易于使用,并且非常人性化。

我喜欢它的两个原因

  • 代码量小,简单直观
  • 巧妙地使用 "Rust" 语法

在这里,我将从用户的角度来谈谈 "argh" 的使用,作为我自己一个小型的 "提示板"。

命令行参数

首先,让我们创建一个新的项目。自然地,使用 cargo new <argh-demo>

然后,像这样将 argh 添加到我们的依赖项中

[dependencies]
argh = "0.1"

让我们一起来做一些事情,比如实现一个简单的命令行加法器?就像 "a + b"。显然,我们的函数接受两个参数,num1num2

fn add(num1: u16, num2: u16) {
    println!(arg1 + arg2);
}

看看 argh 是如何做的

#[derive(FromArgs)]
/// Add two numbers
struct DemoCli {
    /// the first number.
    #[argh(option)]
    num1: u16,

    /// the second number
    #[argh(option)]
    num2: u16,
}

然后在主函数中将它们连接在一起。

fn main() {
    let cli: DemoCli = argh::from_env();
    add(cli.num1, cli.num2);
}

现在,让我们尝试运行 cargo run 看看会发生什么

Required options not provided:
    --num1
    --num2

尝试 --help 选项,target / debug / argh-demo --help

Usage: target/debug/argh-demo --num1 <num1> --num2 <num2>

Add two numbers

Options:
  --num1            the first number.
  --num2            the second number
  --help            display usage information

嗯,看起来我们不得不添加所有选项 target/debug/argh-demo --num1 1 --num2 2

1 + 2 = 3

子命令

看起来不错,但如果我们目标是完整的计算器,可以通过子命令选择功能,例如 argh-demo add --num1 1-num2 2,这将使我们的设计有所改变。

让我们看看如何修改代码

  1. 首先,在 DemoCli 中声明一个名为 subcommand 的子命令集。

    #[derive(FromArgs)]
    /// A simple calculation tool
    struct DemoCli {
        #[argh(subcommand)]
        subcommand: SubCommands,
    }
    
  2. 定义包含 Add 选项的 SubCommands 结构

    #[derive(FromArgs, PartialEq, Debug)]
    #[argh(subcommand)]
    enum SubCommands {
        Add(AddOptions),
    }
    
  3. AddOptions 添加内容

    #[derive(FromArgs, PartialEq, Debug)]
    /// Add two numbers
    #[argh(subcommand, name = "add")]
    pub struct AddOptions {
        /// the first number.
        #[argh(option)]
        num1: u16,
    
        /// the second number
        #[argh(option)]
        num2: u16,
    }
    

显然,你只需要在主函数中重写调用部分

match cli.subcommand {
    SubCommands::Add(options) => {
        add(options.num1, options.num2);
    }
};

运行 cargo build && ./target/debug/argh-demo --help 来查看我们如何使用这个改进版本。

Usage: ./target/debug/argh-demo <command> [<args>]

A simple calculation tool

Options:
  --help            display usage information

Commands:
  add               Add two numbers

继续使用 1 + 2 = 3 来尝试,target / debug / argh-demo --num1 1 --num2 2

1 + 2 = 3

更好的结构

如果我们的程序有很多选项/子命令需要组织,放在一个文件里会显得很乱。想象一下像 cargo 这样的程序是如何做到的。它们在 commands 文件夹中为每个子命令都设置了单独的文件。

如果我们引入一个 sub 子命令,程序结构将看起来像这样。

├── Cargo.lock
├── Cargo.toml
├── README.md
├── src
│   ├── commands
│   │   ├── add.rs
│   │   ├── mod.rs
│   │   └── sub.rs
│   └── main.rs

由于子命令和相应的 execute 函数都应该移动到 commands 下的相应文件中,所以 main.rs 将会更加简洁

//! Just a demo for argh.

use argh::FromArgs;

mod commands;

#[derive(FromArgs)]
/// A simple calculation tool
struct DemoCli {
    #[argh(subcommand)]
    subcommand: SubCommands,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum SubCommands {
    Add(commands::add::AddOptions),
    Sub(commands::sub::SubOptions),
}

fn main() {
    let cli: DemoCli = argh::from_env();
    match cli.subcommand {
        SubCommands::Add(options) => {
            commands::add::execute(options);
        }
        SubCommands::Sub(options) => {
            commands::sub::execute(options);
        }
    };
}

所以很明显,addsub 模块应该暴露在 commands mod.rs 中。

pub mod add;
pub mod sub;

由于我们将选项整体传递给 execute 函数,因此需要相应地修改 add 模块

use argh::FromArgs;

#[derive(FromArgs, PartialEq, Debug)]
/// Add two numbers
#[argh(subcommand, name = "add")]
pub struct AddOptions {
    /// the first number.
    #[argh(option)]
    num1: u16,

    /// the second number
    #[argh(option)]
    num2: u16,
}

pub fn execute(options: AddOptions) {
    println!(
        "{} + {} = {}",
        options.num1,
        options.num2,
        options.num1 + options.num2
    );
}

下一步只是编写一个简单的 sub 模块

use argh::FromArgs;

#[derive(FromArgs, PartialEq, Debug)]
/// Sub two numbers
#[argh(subcommand, name = "sub")]
pub struct SubOptions {
    /// the first number.
    #[argh(option)]
    num1: i16,

    /// the second number
    #[argh(option)]
    num2: i16,
}

pub fn execute(options: SubOptions) {
    println!(
        "{} - {} = {}",
        options.num1,
        options.num2,
        options.num1 - options.num2
    );
}

像往常一样,使用 --help 选项查看用法

Usage: target/debug/argh-demo <command> [<args>]

A simple calculation tool

Options:
  --help            display usage information

Commands:
  add               Add two numbers
  sub               Sub two numbers

最后再次测试函数

  1. target/debug/argh-demo add --num1 1 --num2 2

    1 + 2 = 3
    
  2. target/debug/argh-demo sub --num1 1 --num2 2

    1 - 2 = -1
    

依赖项

~0.5–1MB
~24K SLoC