2.23 Go之flag包:命令行参数解析

2.23 Go之flag包:命令行参数解析

背景阐述

在编写命令行程序(工具、server)时,我们有时需要对命令参数进行解析。Go语言中的flag包中,提供了命令行参数解析的功能

命令行工具包含的几个概念

  • 命令行参数(或参数):是指运行程序时提供的参数;

  • 已定义命令行参数:是指程序中通过flag.Type这种形式定义了的参数;

  • flag(non-flag)命令行参数(或保留的命令行参数):简单理解为flag包不能解析的参数。

优点:

Go语言内置的flag包实现了命令行参数的解析,flag包使得开发命令行工具更为简单。

定义命令行参数

两个函数对命令行参数进行定义:

  • flag.Type()

  • flag.TypeVar()


flag.Type()

基本格式:

flag.Type(flag 名, 默认值, 帮助信息) *Type
/*
默认值和帮助信息是对参数的说明
*/

Type可以是IntStringBool等,返回值为一个相应类型的指针

示例代码:

name := flag.String("name", "张三", "姓名")
age := flag.Int("age", 18, "年龄")
married := flag.Bool("married", false, "婚否")
delay := flag.Duration("d", 0, "时间间隔")
/*
name、age、married、delay 均为对应类型的指针
*/

flag.TypeVar()

基本格式:

flag.TypeVar(Type 指针, flag 名, 默认值, 帮助信息)
/*
默认值和帮助信息是对参数的说明
*/

TypeVar可以是IntVarStringVarBoolVar等,其功能为将flag绑定到一个变量上

示例:

var name string
var age int
var married bool
var delay time.Duration
flag.StringVar(&name, "name", "张三", "姓名")
flag.IntVar(&age, "age", 18, "年龄")
flag.BoolVar(&married, "married", false, "婚否")
flag.DurationVar(&delay, "d", 0, "时间间隔")

解析命令行参数

Go通过调用flag.Parse()对命令行参数进行解析:

  • -flag:只支持bool类型;

  • -flag=x;布尔类型的参数必须使用等号的方式指定

  • -flag x:只支持非bool类型。

flag参数类型

支持的类型有:bool、int、int64、uint、uint64、float、float64、string、duration

flag 参数有效值
字符串 flag 合法字符串
整数 flag 1234、0664、0x1234 等类型,也可以是负数
浮点数 flag 合法浮点数
bool 类型 flag 1、0、t、f、T、F、true、false、TRUE、FALSE、True、False
时间段 flag 任何合法的时间段字符串,如“300ms”、“-1.5h”、“2h45m”, 合法的单位有“ns”、“us”、“µs”、“ms”、“s”、“m”、“h”

flag包其他函数

flag.Args()  //返回命令行参数后的其他参数,以 []string 类型
flag.NArg()  //返回命令行参数后的其他参数个数
flag.NFlag() //返回使用的命令行参 数个数

示例代码:

定义和解析命令行参数:

package main

import (
   "flag"
   "fmt"
)

/*
调用parse函数对命令行参数进行解析
*/
// 定义命令行参数
var Input_pstrName = flag.String("name", "Lucifer", "input user name")
var Input_piAge = flag.Int("age", 22, "input user age")
var Input_flagvar int

// 定义一个初始化函数,返回一个参数变量指针
func Init() {
   flag.IntVar(&Input_flagvar, "flagname", 1234, "参数帮助信息!")
}

// 调用parse函数解析命令行参数
func main() {
   Init()
   flag.Parse()
   fmt.Printf("args=%s, num=%d\n", flag.Args(), flag.NArg())
   for i := 0; i != flag.NArg(); i++ {
       fmt.Printf("arg[%d]=%s\n", i, flag.Arg(i))
  }
   fmt.Println("name=", *Input_pstrName)
   fmt.Println("age=", *Input_piAge)
   fmt.Println("flagname=", Input_flagvar)
}

自定义Value:

创建自定义flag,只要实现flag.Value接口即可(要求receiver是指针类型):

flag.Var(&flagVal, "name", "help message for flagname")

示例代码:

解析喜欢的编程语言,并直接解析到slice中--->定义如下sliceValue类型,然后实现Value接口

package main

import (
   "flag"
   "fmt"
   "strings"
)

// 定义一个类型,用于增加该类型的方法
type sliceValue []string

// 定义一个创建该类型的函数--->返回该类型的指针
func newSliceValue(vals []string, p *[]string) *sliceValue {
   *p = vals
   // 返回指针--->转型
   return (*sliceValue)(p)
}

// 定义一个value接口,里面实现的获取字符串和设置字符串的函数
type Value interface {
   String() string
   Set(string) error
}

// sliceValue类型实现flag包中的Value接口,将命令行接收到的值用,分隔存到slice里
func (s *sliceValue) Set(val string) error {
   // 用逗号分割存到slice中--->*+变量是获取指针类型变量的具体变量
   *s = sliceValue(strings.Split(val, ","))
   return nil
}

// 实现set函数
func (s *sliceValue) String() string {
   *s = sliceValue(strings.Split("我全都要", ","))
   return "It's none of my business"
}

/*
可执行文件名 -slice="java,go" 最后将输出[java,go]
可执行文件名 最后将输出[default is me]
*/
// 调用函数
func main() {
   // 定义一个切片变量
   var languages []string
   // 使用flag.Var函数自定义flag
   flag.Var(newSliceValue([]string{}, &languages), "slice", "我喜欢的语言是:")
   // 解析参数
   flag.Parse()

   // 打印切片变量
   fmt.Println(languages)
}

通过-slice go,php这样的形式传递参数,languages 得到的就是 [go, php],如果不加-slice参数则打印默认值[我全都要]

posted @ 2022-02-28 10:14  俊king  阅读(446)  评论(0)    收藏  举报