go命令行参数flag使用及解读

go命令行参数flag使用及解读

1. 基本使用

package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
)

var (
	ServiceNameVersion string
	ServiceHost string
	ServicePort string
	ServiceProto string
	ServiceConfPath string
	ServiceInnerPort string
	ServiceOuterPort string
	OutputVersion bool
	test          bool
	VERSION       = 2.2
)


func main() {
	// 当和第三方包同时使用-v作为启动参数时,不做特殊处理会panic
	// 此处使用新的CommandLine
	flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)

	// 解析命令行参数
	flag.StringVar(&ServiceNameVersion, "s", "", "Service Name, can add version")
	flag.StringVar(&ServiceHost, "host", "127.0.0.1", "Service Host")
	flag.StringVar(&ServicePort, "p", "", "Service Port")
	flag.StringVar(&ServiceProto, "proto", "default", "Service Protocol: http h2c h2")
	flag.StringVar(&ServiceConfPath, "config", "$PORT/etc", "Service config path")
	flag.StringVar(&ServiceInnerPort, "inport", "", "inner listen port ")
	flag.StringVar(&ServiceOuterPort, "outport", "", "outer listen port")
	flag.BoolVar(&OutputVersion, "v", false, "Output Mesher Version Info")
	//flag.BoolVar(&test, "v", false, "Output Mesher Version Info")//打开注释会报错,重复注册v

	flag.Parse()

	// 当和第三方包同时使用-v作为启动参数时,不做特殊处理会panic
	// 此处使用新的CommandLine
	flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)

	fmt.Println(OutputVersion)
	//输出上述所有的全局变量
	fmt.Println(ServiceNameVersion)
	fmt.Println(ServiceHost)
	fmt.Println(ServicePort)
	fmt.Println(ServiceProto)
	fmt.Println(os.ExpandEnv(ServiceConfPath))//这个os.ExpandEnv可以把ServiceConfPath中带的$的部分转换成环境变量中的值
	fmt.Println(ServiceInnerPort)
	fmt.Println(ServiceOuterPort)
	fmt.Println("Go Version:", runtime.Version())
	// 输出版本号,直接退出
	if OutputVersion {
		fmt.Println(VERSION)
		os.Exit(0)
	}
	 
}

因为直接用的flag包提供的一个全局变量,可能会和其他包冲突panic,原理就像我注释的那一行一样,自己测试一下,所以上述代码重置了CommandLine,当然也可以自己定义一个新的FlagSet类型的变量不用全局变量。
在这里插入图片描述

2. 部分源码解读

重复注册部分
在这里插入图片描述

解析命令行参数部分

在这里插入图片描述
在这里插入图片描述

func (f *FlagSet) parseOne() (bool, error) {
	if len(f.args) == 0 {
		return false, nil
	}
    //第一个命令行参数,如果长度小于2或者第一个字符不是-,解析失败
	s := f.args[0]
	if len(s) < 2 || s[0] != '-' {
		return false, nil
	}
    //获取命令行参数对应的值,如果单纯两个--就解析失败
	numMinuses := 1
	if s[1] == '-' {
		numMinuses++
		if len(s) == 2 { // "--" terminates the flags
			f.args = f.args[1:]
			return false, nil
		}
	}
    //例如--p,这里name就是p
	name := s[numMinuses:]
	if len(name) == 0 || name[0] == '-' || name[0] == '=' {
		return false, f.failf("bad flag syntax: %s", s)
	}

	// it's a flag. does it have an argument?
	f.args = f.args[1:]
	hasValue := false
	value := ""
    //如果name中带有=,那么后面那一段就是value,例如--p=2202,value就等于2202,然后hasvalue就为true,name就变成p了
	for i := 1; i < len(name); i++ { // equals cannot be first
		if name[i] == '=' {
			value = name[i+1:]
			hasValue = true
			name = name[0:i]
			break
		}
	}

    //判断name存不存在,不存在判断是不是help或者h都不是就返回error
	flag, ok := f.formal[name]
	if !ok {
		if name == "help" || name == "h" { // special case for nice help message.
			f.usage()
			return false, ErrHelp
		}
		return false, f.failf("flag provided but not defined: -%s", name)
	}

    //判断这个参数是不是bool类型像我们之前的v参数就符合这个条件,这个boolFlag是一个接口,可以去看看源码
	if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
		//判断刚刚那个hasValue是不是true也就是说最开始那个name变量中包不包含=,这种bool是一个特殊类型,传值只能=来传
        //ture就把=后面的value值赋值给最开始传入的指针
        if hasValue {
			if err := fv.Set(value); err != nil {
				return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err)
			}
		} else {
            //false就默认为true
			if err := fv.Set("true"); err != nil {
				return false, f.failf("invalid boolean flag %s: %v", name, err)
			}
		}
	} else {
        //不是bool类型就判断hasValue以及剩余的arg
		// It must have a value, which might be the next argument.
		if !hasValue && len(f.args) > 0 {
			// value is the next arg 参数对应的值就是下一个参数
			hasValue = true
			value, f.args = f.args[0], f.args[1:]
		}
        //如果没有下一个参数了就解析失败例如直接-p,后面没有值了
		if !hasValue {
			return false, f.failf("flag needs an argument: -%s", name)
		}
        //然后把上面赋值的value传给指针
		if err := flag.Value.Set(value); err != nil {
			return false, f.failf("invalid value %q for flag -%s: %v", value, name, err)
		}
	}
	if f.actual == nil {
		f.actual = make(map[string]*Flag)
	}
	f.actual[name] = flag
	return true, nil
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值