欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關(guān)于Golang標準庫flag的全面講解

 更新時間:2022年09月06日 09:09:06   作者:程序員讀書???????  
這篇文章主要介紹了關(guān)于Golang標準庫flag的全面講解,這個庫的代碼量只有1000行左右,卻提供了非常完善的命令行參數(shù)解析功能,更多相關(guān)內(nèi)容需要的朋友可以參考一下

前言:

今天來聊聊Go語言標準庫中一個非常簡單的庫flag,這個庫的代碼量只有1000行左右,卻提供了非常完善的命令行參數(shù)解析功能。

命令行參數(shù)

如果你有使用過類Unix(比如MacOS,Linux)等操作系統(tǒng),相信你應(yīng)該明白命令參數(shù)是什么,比如下面的兩條命令:

$ mysql -u root -p 123456
$ ls -al

第一條命令是MySQL的客戶端,其-u root-p 123456就是命令行參數(shù),第二條命令用于顯示當前目錄的文件及目錄,該命令中-al就是命令行參數(shù)。

flag庫的作用就是幫我們將命令后面的選項參數(shù)解析到對應(yīng)的變量中。

使用詳解

要了解一個庫,須從使用開始,下面我們通過一個簡單的示例來快速了解flag庫的使用,這個示例可以接收從命令行傳遞的用于連接數(shù)據(jù)庫的參數(shù),

代碼如下:

package main
import (
	"flag"
	"fmt"
)

var (
	host     string
	dbName   string
	port     int
	user     string
	password string
)
func main() {

	flag.StringVar(&host, "host", "", "數(shù)據(jù)庫地址")
	flag.StringVar(&dbName, "db_name", "", "數(shù)據(jù)庫名稱")
	flag.StringVar(&user, "user", "", "數(shù)據(jù)庫用戶")
	flag.StringVar(&password, "password", "", "數(shù)據(jù)庫密碼")
	flag.IntVar(&port, "port", 3306, "數(shù)據(jù)庫端口")
	flag.Parse()
	fmt.Printf("數(shù)據(jù)庫地址:%s\n", host)
	fmt.Printf("數(shù)據(jù)庫名稱:%s\n", dbName)
	fmt.Printf("數(shù)據(jù)庫用戶:%s\n", user)
	fmt.Printf("數(shù)據(jù)庫密碼:%s\n", password)
	fmt.Printf("數(shù)據(jù)庫端口:%d\n", port)
}

在命令行窗口輸入以下命令,開始運行程序

go run main.go -host=localhost -user=test -password=123456 -db_name=test -port=3306

運行結(jié)束,輸出結(jié)果如下所示:

數(shù)據(jù)庫地址:localhost
數(shù)據(jù)庫名稱:test
數(shù)據(jù)庫用戶:test
數(shù)據(jù)庫密碼:123456
數(shù)據(jù)庫端口:3306

上面的示例就是一個解析命令行選項參數(shù)的模板,包括下面三個步驟:

  • 定義好接收參數(shù)的變量。
  • 調(diào)用flag.StringVar()等函數(shù)將命令行選項與變量綁定。
  • 調(diào)用flag.Parse()函數(shù),開始解析變量。

在上面程序中,我們用了StringVar函數(shù)綁定字符串類型的參數(shù),用了IntVar函數(shù)綁定整數(shù)類型的參數(shù),除了字符串和整型,flag支持boolean,Duration,float64,Int64,uint,uint64等類型,下面是這些函數(shù)的定義,用法與StringVar相同。

func BoolVar(p *bool, name string, value bool, usage string)
func DurationVar(p *time.Duration, name string, value time.Duration, usage string)
func Float64Var(p *float64, name string, value float64, usage string)
func Int64Var(p *int64, name string, value int64, usage string)
func IntVar(p *int, name string, value int, usage string)
func StringVar(p *string, name string, value string, usage string)
func Uint64Var(p *uint64, name string, value uint64, usage string)
func UintVar(p *uint, name string, value uint, usage string)

上面列出的函數(shù)帶有Var后綴,表示需要我們自己傳遞一個變量去接收命令行參數(shù),而flag在這些函數(shù)有基礎(chǔ)上,封裝了下面列表的函數(shù),這些函數(shù)沒有Var后綴,跟上面的函數(shù)相比少了一個參數(shù),卻多了一個返回值,這個返回值就是接收命令參數(shù)的變量指針。

func Bool(name string, value bool, usage string) *bool
func Duration(name string, value time.Duration, usage string) *time.Duration
func Float64(name string, value float64, usage string) *float64
func Int(name string, value int, usage string) *int
func Int64(name string, value int64, usage string) *int64
func String(name string, value string, usage string) *string
func Uint(name string, value uint, usage string) *uint
func Uint64(name string, value uint64, usage string) *uint64

所以我們把上面的示例改寫為以下的樣子:

package main
import (
	"flag"
	"fmt"
)
func main() {
	host := flag.String("host", "", "數(shù)據(jù)庫地址")
	dbName := flag.String("db_name", "", "數(shù)據(jù)庫名稱")
	user := flag.String("user", "", "數(shù)據(jù)庫用戶")
	password := flag.String("password", "", "數(shù)據(jù)庫密碼")
	port := flag.Int("port", 3306, "數(shù)據(jù)庫端口")

	flag.Parse()
	fmt.Printf("數(shù)據(jù)庫地址:%s\n", *host)
	fmt.Printf("數(shù)據(jù)庫名稱:%s\n", *dbName)
	fmt.Printf("數(shù)據(jù)庫用戶:%s\n", *user)
	fmt.Printf("數(shù)據(jù)庫密碼:%s\n", *password)
	fmt.Printf("數(shù)據(jù)庫端口:%d\n", *port)
}

另外,運行程序時,在后面跟上-h--help來查看命令的參數(shù)選項,如:

go run main.go --help
Usage of main:
  -db_name string
        數(shù)據(jù)庫名稱
  -host string
        數(shù)據(jù)庫地址
  -password string
        數(shù)據(jù)庫密碼
  -port int
        數(shù)據(jù)庫端口 (default 3306)
  -user string
        數(shù)據(jù)庫用戶

選項語法

flag支持以下三種命令行格式,參數(shù)前面的-也可以換成--,在flag庫中,--并不是表示長選項的意思。

cmd -flag
cmd -flag=x
cmd -flag x
  • 第一種只用布爾值的選項,如果該參數(shù)出現(xiàn),則為true,不出則為默認值,而其他數(shù)據(jù)類型不能使用這種格式傳值。
  • 第二種可適用任何類型,因此也是最常用的格式。
  • 第三種不可用于布爾值的選項。

flag在解析參數(shù)時,如果遇到第一個非選項參數(shù)(不是以-或--開頭的)或終止符--,就會停止解析,

比如上面的示例中,我們將運行命令改成下面的樣子:

go run main.go -host=localhost noflag -user=test -password=123456 -db_name=test -port=3306

運行結(jié)果如下,可以看到解析-host參數(shù)之后遇到了noflag這樣的非選項參數(shù),flag就停止解析了,所以后面的參數(shù)都只輸出了默認值。

數(shù)據(jù)庫地址:localhost
數(shù)據(jù)庫名稱:
數(shù)據(jù)庫用戶:
數(shù)據(jù)庫密碼:
數(shù)據(jù)庫端口:3306

整數(shù)類型的參數(shù)可以接收十進制、八進制,十六進制的參數(shù),布爾型可以接收下面列出參數(shù)

1, 0, t, f, T, F, true, false, TRUE, FALSE, True, False

Duration類型的參數(shù)接收可以被time.ParseDuration()解析的參數(shù)。

flag是怎么解析參數(shù)的?

我們知道flag庫是用于命令行解析的,但其內(nèi)部是怎么解析的呢?下面我們來分析一下

一個命令行參數(shù)包含以下四個部分:

  • 接收參數(shù)的變量
  • 參數(shù)名稱
  • 默認值
  • 參數(shù)說明

所以flag設(shè)置命令行參數(shù)的函數(shù)有四個參數(shù),比如:

var p int
flag.IntVar(&p,"port",3306,"數(shù)據(jù)庫端口")

flag內(nèi)部有一個名稱CommandLine的變量,其類型為FlagSet,如:

var CommandLine = NewFlagSet(os.Args[0], ExitOnError)

FlagSet就是一個命令行參數(shù)的集合體,當我們調(diào)用諸如IntVar這類的函數(shù)時,就是將命令行的默認值、參數(shù)說明,參數(shù)名稱接收參數(shù)的變量等信息告訴flag庫,而flag內(nèi)部會讓CommandLine來處理,用這些信息創(chuàng)建Flag類型的變量,將添加到這個集合體中。

flag := &Flag{name, usage, value, value.String()}

最后,當我們調(diào)用flag.Parse函數(shù)時,實際就是調(diào)用FlagSet結(jié)構(gòu)體的Parse函數(shù)將命令參數(shù)解析到變量中,flag.Parse函數(shù)代碼如下:

func Parse() {
	CommandLine.Parse(os.Args[1:])
}

從上面的代碼我們也可以看出來,F(xiàn)lagSet的Parse函數(shù)最終是通過獲取os.Args數(shù)組的數(shù)據(jù)來解析命令行參數(shù)的。

即然我們知道flag是通過類型為FlagSet的變量CommandLine來處理命令行參數(shù)的,那其實我們也可以自己創(chuàng)建一個FlagSet類型的變量來處理命令行參數(shù),

所以我們可以將上面的例改成下面的樣子:

package main
import (
	"flag"
	"fmt"
	"os"
)
func main() {
    //自己創(chuàng)建一個命令行參數(shù)的集合
	var flagSet = flag.NewFlagSet("my flag", flag.ExitOnError)

	host := flagSet.String("host", "", "數(shù)據(jù)庫地址")
	dbName := flagSet.String("db_name", "", "數(shù)據(jù)庫名稱")
	user := flagSet.String("user", "", "數(shù)據(jù)庫用戶")
	password := flagSet.String("password", "", "數(shù)據(jù)庫密碼")
	port := flagSet.Int("port", 3306, "數(shù)據(jù)庫端口")

    //解析命令行參數(shù),從os.Args的第二個元素開始,第一個元素是命令本身
	flagSet.Parse(os.Args[1:])

	fmt.Printf("數(shù)據(jù)庫地址:%s\n", *host)
	fmt.Printf("數(shù)據(jù)庫名稱:%s\n", *dbName)
	fmt.Printf("數(shù)據(jù)庫用戶:%s\n", *user)
	fmt.Printf("數(shù)據(jù)庫密碼:%s\n", *password)
	fmt.Printf("數(shù)據(jù)庫端口:%d\n", *port)

}

另外,我們已經(jīng)知道了flag解析參數(shù)的來源是os.Args這樣的字符串數(shù)組,那我們也可以模擬一個這樣的數(shù)組,將數(shù)組解析到變量之中,而不需要去解析os.Args數(shù)組,

下面的例子就是這樣做的:

package main
import (
	"flag"
	"fmt"
)
func main() {
    //模擬os.Args數(shù)組,定義一個參數(shù)數(shù)組
	var params = []string{"-host", "127.0.0.1", "-db_name", "test", "-user", "test", "-password", "abcdef", "-port", "13306"}

	var flagSet = flag.NewFlagSet("my flag", flag.ExitOnError)

	host := flagSet.String("host", "", "數(shù)據(jù)庫地址")
	dbName := flagSet.String("db_name", "", "數(shù)據(jù)庫名稱")
	user := flagSet.String("user", "", "數(shù)據(jù)庫用戶")
	password := flagSet.String("password", "", "數(shù)據(jù)庫密碼")
	port := flagSet.Int("port", 3306, "數(shù)據(jù)庫端口")

    //解析自定義的參數(shù)數(shù)組
	flagSet.Parse(params)
	fmt.Printf("數(shù)據(jù)庫地址:%s\n", *host)
	fmt.Printf("數(shù)據(jù)庫名稱:%s\n", *dbName)
	fmt.Printf("數(shù)據(jù)庫用戶:%s\n", *user)
	fmt.Printf("數(shù)據(jù)庫密碼:%s\n", *password)
	fmt.Printf("數(shù)據(jù)庫端口:%d\n", *port)

}

運行程序,在命令后面不需要跟命令行參數(shù),如下:

go run main.go

運行后結(jié)果如下:

數(shù)據(jù)庫地址:127.0.0.1
數(shù)據(jù)庫名稱:test
數(shù)據(jù)庫用戶:test
數(shù)據(jù)庫密碼:abcdef
數(shù)據(jù)庫端口:13306

自定義數(shù)據(jù)類型

如果flag提供的數(shù)據(jù)類型不能滿足我們的需要,我們也可以自定義類型,自定義類型需要實現(xiàn)flag中的Value接口,該接口定義如下:

type Value interface {
	String() string
	Set(string) error
}

Value類型的String()用于打印數(shù)值,而Set方法則用于flag包將命令行參數(shù)設(shè)置到Value類型中。

下面是一個自定義類型的示例程序:

package main

import (
	"flag"
	"fmt"
	"strings"
)
type Users []string
func (u *Users) Set(val string) error {
	*u = strings.Split(val, ",")
	return nil
}
func (u *Users) String() string {
	str := "["
	for _, v := range *u {
		str += v
	}
	return str + "]"
}

func main() {
	var u Users
	flag.Var(&u, "u", "用戶列表")
	flag.Parse()

	for _, v := range u {
		fmt.Println(v)
	}
}

運行結(jié)果:

 go run main.go -u=小明,小張,小紅,小剛
小明
小張
小紅
小剛

從上面的示例中我們可以總結(jié)自定義類型的幾個步驟:

  • 定義一個實現(xiàn)flag.Value接口的類型,并實現(xiàn)String和Set方法。
  • 使用flag.Var函數(shù)將類型綁定到類型參數(shù)。
  • 調(diào)用flag.Parse()解析命令行參數(shù)。

短選項

我們在使用Linux命令的時候,發(fā)現(xiàn)很多命令的參數(shù)是有分短選項和長選項的,不過flag庫并不支持短選項;當然也有變通的方式,比如我們可以自己定義一個長選項和短選項,

如:

var port int
flag.IntVar(&port, "p", 3306, "數(shù)據(jù)庫端口")
flag.IntVar(&port, "port", 3306, "數(shù)據(jù)庫端口")
flag.Parse()

fmt.Println(port)

上面的程序中,我們定義了pport兩個參數(shù),并將其綁定到變量port,因此通過下面兩條命令都可以獲取參數(shù):

$ go run main.go -p 111
$ go run main.go -port 111

小結(jié)

在這篇文章中,我們?nèi)嬷v解了flag庫,看完這篇文章,相信你可以學習到以下幾點:

  • 在Go程序員中如何使用flag庫解析命令行參數(shù)。
  • flag庫解析命令行參數(shù)的原理。
  • 怎么讓flag庫支持我們自定義的數(shù)據(jù)類型。
  • 怎么定義命令行參數(shù)短選項。

到此這篇關(guān)于關(guān)于Golang標準庫flag的全面講解的文章就介紹到這了,更多相關(guān)Golang標準庫flag內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • go將request?body綁定到不同的結(jié)構(gòu)體中教程

    go將request?body綁定到不同的結(jié)構(gòu)體中教程

    這篇文章主要為大家介紹了go將request?body綁定到不同的結(jié)構(gòu)體中教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • golang值接收者和指針接收者的區(qū)別介紹

    golang值接收者和指針接收者的區(qū)別介紹

    這篇文章主要介紹了golang值接收者和指針接收者的區(qū)別,它和函數(shù)的區(qū)別在于方法有一個接收者,給一個函數(shù)添加一個接收者,那么它就變成了方法,接收者可以是值接收者,也可以是指針接收者,本文通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-08-08
  • 使用go語言實現(xiàn)查找兩個數(shù)組的異同操作

    使用go語言實現(xiàn)查找兩個數(shù)組的異同操作

    這篇文章主要介紹了使用go語言實現(xiàn)查找兩個數(shù)組的異同操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go語言使用HTTP包創(chuàng)建WEB服務(wù)器的方法

    Go語言使用HTTP包創(chuàng)建WEB服務(wù)器的方法

    這篇文章主要介紹了Go語言使用HTTP包創(chuàng)建WEB服務(wù)器的方法,結(jié)合實例形式分析了Go語言基于HTTP包創(chuàng)建WEB服務(wù)器客戶端與服務(wù)器端的實現(xiàn)方法與相關(guān)注意事項,需要的朋友可以參考下
    2016-07-07
  • go?generate代碼自動生成指南

    go?generate代碼自動生成指南

    這篇文章主要介紹了go?generate代碼自動生成指南,本文將探討?go?generate?命令的使用方法、原理以及一些實際應(yīng)用場景,希望讀者能夠更好地理解和運用這個強大的工具
    2024-01-01
  • 如何在Go中使用切片容量和長度

    如何在Go中使用切片容量和長度

    這篇文章主要介紹了如何在Go中使用切片容量和長度,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • golang 網(wǎng)絡(luò)框架之gin的使用方法

    golang 網(wǎng)絡(luò)框架之gin的使用方法

    這篇文章主要介紹了golang 網(wǎng)絡(luò)框架之gin的使用方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11
  • Go疑難雜癥講解之為什么nil不等于nil

    Go疑難雜癥講解之為什么nil不等于nil

    在日常開發(fā)中,可能一不小心就會掉進?Go?語言的某些陷阱里,而本文要介紹的?nil?≠?nil?問題,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-10-10
  • Golang中函數(shù)的使用方法詳解

    Golang中函數(shù)的使用方法詳解

    這篇文章主要詳細介紹了Golang中函數(shù)的使用方法,文中有詳細的示例代碼,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2023-05-05
  • 使用Go語言解決Scan空格結(jié)束輸入問題

    使用Go語言解決Scan空格結(jié)束輸入問題

    這篇文章主要為大家介紹了使用Go語言來解決Scan空格結(jié)束輸入問題,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2021-11-11

最新評論