• go的解析命令行库go-flags


    简介

    Go的标准库flag由于其有不支持短选项,选项定义比较繁琐,默认只支持有限的数据类型。为了解决这些问题,出现了不少第三方解析命令行选项的库,go-flags就是其中一个。

    go-flags提供了比标准库flag更多的选项,它利用结构体的标签tag和反射提供了一个方便、简洁的接口。除了基本的功能,还提供了其他丰富的特性:

    • 支持短选项-v和长选项-verbose

    • 支持短选项合写,如-aux

    • 同一选项可以设置多个值

    • 支持所有基础类型和map类型,甚至函数

    • 支持命名空间和选项组

      等等…

    快速开始

    使用go get安装第三方库

    $ go get github.com/jessevdk/go-flags
    
    • 1

    快速开始

    type Option struct {
    	Names []string `short:"n" long:"name" description:"names of user"`
    }
    
    func main() {
    	var opt Option
    	flags.Parse(&opt)
    
    	fmt.Println(opt.Names)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行程序

    $ go run main.go --name test1 --name test2 --name test3
    [test1 test2 test3]
    
    • 1
    • 2

    使用go-flags的一般步骤:

    1. struct结构体的tag中定义选项。short定义短选项,long定义长选项,description设置帮助信息。
    2. 声明选项变量。
    3. flag类似地,调用flags.Parse()开始解析选项。

    基本特性

    支持丰富的数据类型

    go-flags相比标准库flag支持更丰富的数据类型:

    • 所有基本的数据类型(包括符号整数和无符号整数,浮点数,布尔类型和字符串)及它们的切片
    • map类型。不过仅支持键为string,值为基础类型。
    • 函数类型。

    Tips

    切片类型选项,遇到相同的选项时,值会被追加到切片中。而非切片类型选项,如果遇到相同选项,后出现的值会覆盖先出现的值。

    选项是函数类型:函数类型的参数有且仅有一个,作为函数的入参。

    选项是map类型:键只能是string类型,值是基本的数据类型,格式为key:value

    示例

    main.go:

    type Option struct {
    	Names    []string       `short:"n" long:"name" description:"names of users"`
    	Age      int            `short:"a" long:"age" description:"age of user"`
    	Pointers []*string      `short:"p" long:"pointer" description:"pointers of *string"`
    	Call     func(int)      `short:"c" long:"call" description:"call function"`
    	Values   map[string]int `short:"v" long:"value" description:"values of user"`
    }
    
    func main() {
    	var opt Option
    	opt.Call = func(v int) {
    		// 预先定义好call属性的函数类型的实现,然后parse后会自动进行调用
    		fmt.Println("call function:", v)
    	}
    
    	if _, err := flags.Parse(&opt); err != nil {
    		panic("flags parse failed")
    	}
    
    	fmt.Println(opt.Names)
    	fmt.Println(opt.Age)
    	for _, p := range opt.Pointers {
    		fmt.Println(*p)
    	}
    	fmt.Println(opt.Values)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    terminal:

    $ go run main.go --name test1 -n test2 -n test3 -a 18 -a 19 -p pointer -c 18 -v k1:18
    call function: 18
    [test1 test2 test3]
    19
    pointer
    map[k1:18]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    常用设置

    required为true时,对应的选项必须设置值,否则会抛出ErrRequired错误

    default用于设置选项的默认值,即选项如果没有设置值的时候,会使用此默认值

    main.go

    type Config struct {
    	Name   string `short:"n" required_default:"true"`
    	Gender string `short:"g" default:"man"`
    }
    
    func main() {
    	var config Config
    
    	if _, err := flags.Parse(&config); err != nil {
    		log.Fatal("parse failed:", err)
    	}
    
    	fmt.Println(config.Name)
    	fmt.Println(config.Gender)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    terminal

    $ go run main.go -n test
    test
    man
    
    • 1
    • 2
    • 3

    高级特性

    选项分组

    main.go

    type Option struct {
    	Name    string        `long:"name"`
    	Info    InfoOption    `group:"info"`
    	Contact ContactOption `group:"contact"`
    }
    
    type InfoOption struct {
    	Gender bool `long:"gender"`
    	Age    int  `long:"age"`
    }
    
    type ContactOption struct {
    	Email string `long:"email"`
    	Phone string `long:"phone"`
    }
    
    func main() {
    	var opt Option
    	if _, err := flags.Parse(&opt); err != nil {
    		log.Fatalln("flags parse failed:", err)
    	}
    
    	fmt.Println(opt.Name)
    	fmt.Println(opt.Info)
    	fmt.Println(opt.Contact)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    将分组的选项拆分到另外两个结构体当中,并且在父结构体中使用时,加上Tag:group:""

    terminal

    $ go run main.go --name test --gender --age 18 --email abc@example.com --phone 1111111
    test
    {true 18}
    {abc@example.com 1111111}
    
    • 1
    • 2
    • 3
    • 4

    参考

    每日一库之go-flags

  • 相关阅读:
    基于yolov5+streamlit目标检测演示系统设计
    【数据结构】快排的详细讲解
    第2章 MyBatis的核心配置
    ceph debug
    项目实战:组件扫描(4)-筛选带有RequestMapping注解的bean实例
    Kimi Chat,不仅仅是聊天!深度剖析Kimi Chat 5大使用场景!
    2023山东建筑大学考研介绍
    OpenCV图像特征提取学习二,Shi-Tomasi 角点检测算法
    IPWorks SFTP Delphi版—组件消耗的资源
    SpringBoot集成mybatis分包配置多数据源
  • 原文地址:https://blog.csdn.net/weixin_45747080/article/details/126665942