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

Golang?基于flag庫(kù)實(shí)現(xiàn)一個(gè)簡(jiǎn)單命令行工具

 更新時(shí)間:2022年09月06日 08:59:20   作者:ag9920  
這篇文章主要介紹了Golang基于flag庫(kù)實(shí)現(xiàn)一個(gè)簡(jiǎn)單命令行工具,Golang標(biāo)準(zhǔn)庫(kù)中的flag庫(kù)提供了解析命令行選項(xiàng)的能力,我們可以基于此來(lái)開發(fā)命令行工具,下文詳細(xì)介紹。需要的小伙伴可以參考一下

前言

Golang 標(biāo)準(zhǔn)庫(kù)中的 flag 庫(kù)提供了解析命令行選項(xiàng)的能力,我們可以基于此來(lái)開發(fā)命令行工具。

假設(shè)我們想做一個(gè)命令行工具,我們通過(guò)參數(shù)提供【城市】,它自動(dòng)能夠返回當(dāng)前這個(gè)【城市】的天氣狀況。這樣一個(gè)簡(jiǎn)單的需求,今天我們就來(lái)試一下,看怎樣實(shí)現(xiàn)。

flag 庫(kù)

Package flag implements command-line flag parsing.

flag 庫(kù) 能夠支持基礎(chǔ)的命令行 flag 解析。使用起來(lái)并不復(fù)雜,

我們可以針對(duì) string, integer, bool 三種類型來(lái)定義 flag,如:flag.String(), Bool(), Int()。

比如下面這樣,我們就定義了一個(gè) -n 的選項(xiàng),默認(rèn)值為 1234, 提示信息為 help message for flag n。返回值是一個(gè) int 的指針。

import "flag"
var nFlag = flag.Int("n", 1234, "help message for flag n")

當(dāng)然,我們也可以直接將 flag 和變量綁定,這里要在上面三種方法的前面加上 Var 即可:

var flagvar int
func init() {
	flag.IntVar(&flagvar, "flagname", 1234, "help message for flagname")
}

區(qū)別只在于首個(gè)參數(shù)是個(gè)指針,直接賦值,而不是 return 回來(lái)。簽名都是類似的,我們看一個(gè) Int64Var:

在所有 flag 都定義好之后,我們調(diào)用 flag.Parse() 方法,將命令行數(shù)據(jù)解析到對(duì)應(yīng)的 flag 中。這之后就可以直接用了:

fmt.Println("ip has value ", *ip)
fmt.Println("flagvar has value ", flagvar)

有時(shí)候我們不止是一個(gè)簡(jiǎn)單的 flag,還需要參數(shù),這個(gè)時(shí)候我們就可以用 flag.Args() 拿到一個(gè) slice,或者直接 flag.Arg(i) 來(lái)拿指定參數(shù),下標(biāo)從 0 開始。

不熟悉的同學(xué)建議多看看看 go by example 的示例,講的很清楚。

從開發(fā)者的角度看,其實(shí)我們只要定義好變量,用 flag.XXVar 來(lái)綁定,最后 flag.Parse 就可以用:

package main

import (
  "fmt"
  "flag"
)
var (
  intflag int
  boolflag bool
  stringflag string
)
func init() {
  flag.IntVar(&intflag, "intflag", 0, "int flag value")
  flag.BoolVar(&boolflag, "boolflag", false, "bool flag value")
  flag.StringVar(&stringflag, "stringflag", "default", "string flag value")
}
func main() {
  flag.Parse()

  fmt.Println("int flag:", intflag)
  fmt.Println("bool flag:", boolflag)
  fmt.Println("string flag:", stringflag)
}

編譯之后我們運(yùn)行一下看看

$ ./main -intflag 12 -boolflag 1 -stringflag test

int flag: 12
bool flag: true
string flag: test

如果沒有設(shè)置 flag 的值,會(huì)取我們?cè)O(shè)置的默認(rèn)值。

flag 支持的解析類型有下面四種:

  • -flag
  • --flag
  • -flag=x
  • -flag x (bool 不能用這個(gè))

有時(shí)候我們只需要一個(gè) flag 就夠了,選項(xiàng)本身就帶著含義,不需要參數(shù)。而有些時(shí)候我們既需要 flag,也需要參數(shù)。注意區(qū)分好場(chǎng)景即可。如果用了第一種和第二種這種不帶參數(shù)的,本質(zhì)含義就是個(gè) bool,出現(xiàn)就是 true,不出現(xiàn)就看默認(rèn)值。

FlagSet

FlagSet 就是一組 flag 定義的集合,在 flag 庫(kù)的底層是一個(gè)結(jié)構(gòu)體:

type FlagSet struct {
	// Usage is the function called when an error occurs while parsing flags.
	// The field is a function (not a method) that may be changed to point to
	// a custom error handler. What happens after Usage is called depends
	// on the ErrorHandling setting; for the command line, this defaults
	// to ExitOnError, which exits the program after calling Usage.
	Usage func()
	// contains filtered or unexported fields
}

注意有一個(gè) Usage 函數(shù),當(dāng)解析 flag 出問(wèn)題時(shí)就會(huì)調(diào)用這個(gè)。前面 flag 庫(kù)封裝的那些能力底層都是共用同一個(gè)默認(rèn)的 CommandLine FlagSet實(shí)現(xiàn)的:

// src/flag/flag.go
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)

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

func IntVar(p *int, name string, value int, usage string) {
  CommandLine.Var(newIntValue(value, p), name, usage)
}

func Int(name string, value int, usage string) *int {
  return CommandLine.Int(name, value, usage)
}

func NFlag() int { return len(CommandLine.actual) }

func Arg(i int) string {
  return CommandLine.Arg(i)
}

func NArg() int { return len(CommandLine.args) }

當(dāng)我們調(diào)用 NewFlagSet 時(shí)需要指定這個(gè)集合的名稱以及對(duì)應(yīng)的錯(cuò)誤處理。

第二個(gè)參數(shù)這個(gè)錯(cuò)誤處理有三種選項(xiàng),flag 已經(jīng)提供:

  • ContinueOnError:發(fā)生錯(cuò)誤后繼續(xù)解析,CommandLine就是使用這個(gè)選項(xiàng);
  • ExitOnError:出錯(cuò)時(shí)調(diào)用os.Exit(2)退出程序;
  • PanicOnError:出錯(cuò)時(shí)產(chǎn)生 panic。

需求拆解

我們的需求很簡(jiǎn)單,提供一個(gè) weather flag,接受輸入的城市名稱,隨后我們返回天氣數(shù)據(jù)即可。

所以,從 flag 的角度看,這里并不復(fù)雜,我們將【城市名稱】綁定到一個(gè) flag 上即可。

關(guān)鍵是要實(shí)現(xiàn)基于城市名稱查天氣的能力。這個(gè)也有公開的網(wǎng)站能實(shí)現(xiàn),參照此前 Golang 教程中給出的 wttr 就可以。大家可以試一下,訪問(wèn) wttr.in/wuhan 將會(huì)展示【武漢】的天氣預(yù)報(bào):

這里其實(shí)比較 trick,由于是網(wǎng)站,并不是公開的 open api,所以返回的數(shù)據(jù)也是 html 格式的,我們要思考一下怎么在命令行展示。

下面我們一步步來(lái)解決。

實(shí)現(xiàn) weather flag

這一步基本是復(fù)用 flag 包提供的能力,這里我們用 StringVar 從命令行拿到值之后寫入變量,這里相對(duì)比較通用,大家以后有需求可以直接改一下即可:

package main
import (
    "flag"
    "fmt"
    "os"
)
type arguments struct {
	weatherCity string
}
func (a *arguments) parseArgs(args []string) error {
	f := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)

	f.StringVar(&a.weatherCity, "weather", "", "check weather")

	f.Usage = func() {
		fmt.Fprintf(os.Stderr, `flags: %s`, os.Args[0])
		f.PrintDefaults()
		os.Exit(1)
	}
	if err := f.Parse(args[1:]); err != nil {
		return err
	}

	return nil
}

func Execute() error {

	args := &arguments{}
	if err := args.parseArgs(os.Args); err != nil {
		fmt.Println(err)
		os.Exit(2)
	}

	// weather
	if args.weatherCity != "" {
                // TODO 實(shí)現(xiàn)根據(jù) city 名稱拿天氣,并打印的效果
	}

	return nil
}

最終在 main() 函數(shù)中直接調(diào)用我們的 Execute 即可,注意我們解析到 weatherCity 不為空時(shí),核心邏輯就在這個(gè)分支,我們留了個(gè) TODO,下面看看怎么解。

天氣數(shù)據(jù)打印

前一節(jié)的 TODO 里本質(zhì)需要我們實(shí)現(xiàn)的簽名很簡(jiǎn)單:

func GetWeather(city string) (string, error)

這樣拿到一個(gè)用字符串表示的天氣數(shù)據(jù),然后回到主流程里一個(gè) fmt.Printf 就可以解決。

而同時(shí)我們也有了 wttr 的能力,可以拿到數(shù)據(jù),只不過(guò)是 html。關(guān)鍵是怎么轉(zhuǎn)字符串。我們一步一步來(lái):

獲取源數(shù)據(jù)

一個(gè)簡(jiǎn)單的 http.Get 拿到 html 數(shù)據(jù)即可,這一步不復(fù)雜,大家直接看代碼:

func getWeatherData(city string) string {
    url := "https://wttr.in/" + city
    response, err := http.Get(url)
    if err != nil {
            return "", err
    }
    all, err := ioutil.ReadAll(response.Body)
    if err != nil {
            return "", err
    }
    weather := string(all)
    return weather
}

數(shù)據(jù)轉(zhuǎn)換

在開源社區(qū),我們找到了 "github.com/JohannesKaufmann/html-to-markdown" 這個(gè)庫(kù)提供 html 轉(zhuǎn)換為 markdown 的能力,而 "github.com/MichaelMure/go-term-markdown" 又可以將 markdown 格式轉(zhuǎn)為可在 terminal 打印的字符串,我們可以通過(guò)這兩步來(lái)轉(zhuǎn)換,實(shí)現(xiàn)整體的 GetWeather 函數(shù):

package weather
import (
	"io/ioutil"
	"net/http"

	md "github.com/JohannesKaufmann/html-to-markdown"
	markdown "github.com/MichaelMure/go-term-markdown"
)
func GetWeather(city string) (string, error) {
	url := "https://wttr.in/" + city
	response, err := http.Get(url)
	if err != nil {
		return "", err
	}
	all, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return "", err
	}
	weather := string(all)
	md := getMD(weather)
	result := markdown.Render(md, 280, 6)
	return string(result), nil
}

func getMD(html string) string {
	converter := md.NewConverter("", true, nil)
	markdown, err := converter.ConvertString(html)
	if err != nil {
		return ""
	}
	return markdown
}

運(yùn)行效果

好了,現(xiàn)在我們實(shí)現(xiàn)了兩步,大家只需要把主流程里 TODO 的注釋換成實(shí)際對(duì)下面 GetWeather 函數(shù)的調(diào)用即可,我們來(lái)看看運(yùn)行效果。

$ opb -weather beijing

完美,一個(gè)展示天氣狀況的命令行工具就做完了。這里的 opb 是我們的 package 名稱,大家可以自己試一下,包名更換為你喜歡的名稱即可。

小結(jié)

其實(shí)開源社區(qū)各種能力基本都有同學(xué)研究過(guò),大家可以打開思路,碰到知識(shí)點(diǎn)就思考如何能落地。筆者也是初學(xué) flag 的時(shí)候本著實(shí)踐的目的來(lái)試一試。正好發(fā)現(xiàn)了 html => markdown => terminal 打印這條路徑,不一定是最好的,但作為一個(gè) toy tool 足夠了。

到此這篇關(guān)于Golang 基于 flag 庫(kù)實(shí)現(xiàn)一個(gè)簡(jiǎn)單命令行工具的文章就介紹到這了,更多相關(guān)Golang  flag內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang結(jié)構(gòu)化日志log/slog包之LogValuer的用法簡(jiǎn)介

    golang結(jié)構(gòu)化日志log/slog包之LogValuer的用法簡(jiǎn)介

    這篇文章主要為大家詳細(xì)介紹了golang結(jié)構(gòu)化日志log/slog包中 LogValuer 和日志記錄函數(shù)的正確包裝方法,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-10-10
  • golang雙指針快速排序的實(shí)現(xiàn)代碼

    golang雙指針快速排序的實(shí)現(xiàn)代碼

    這篇文章主要介紹了golang雙指針快速排序的實(shí)現(xiàn)代碼,通過(guò)實(shí)例代碼補(bǔ)充介紹了Golang實(shí)現(xiàn)快速排序和歸并排序以及堆排序算法全注釋,需要的朋友可以參考下
    2024-03-03
  • 在Go中構(gòu)建并發(fā)TCP服務(wù)器

    在Go中構(gòu)建并發(fā)TCP服務(wù)器

    今天小編就為大家分享一篇關(guān)于在Go中構(gòu)建并發(fā)TCP服務(wù)器的文章,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-10-10
  • 詳解Golang?ProtoBuf的基本語(yǔ)法總結(jié)

    詳解Golang?ProtoBuf的基本語(yǔ)法總結(jié)

    最近項(xiàng)目是采用微服務(wù)架構(gòu)開發(fā)的,各服務(wù)之間通過(guò)gPRC調(diào)用,基于ProtoBuf序列化協(xié)議進(jìn)行數(shù)據(jù)通信,因此接觸學(xué)習(xí)了Protobuf,本文會(huì)對(duì)Protobuf的語(yǔ)法做下總結(jié),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助
    2022-10-10
  • Golang學(xué)習(xí)筆記之延遲函數(shù)(defer)的使用小結(jié)

    Golang學(xué)習(xí)筆記之延遲函數(shù)(defer)的使用小結(jié)

    這篇文章主要介紹了Golang學(xué)習(xí)筆記之延遲函數(shù)(defer),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • go代碼實(shí)現(xiàn)買房貸款月供計(jì)算的方法

    go代碼實(shí)現(xiàn)買房貸款月供計(jì)算的方法

    今天小編就為大家分享一篇關(guān)于go代碼實(shí)現(xiàn)買房貸款月供計(jì)算的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-04-04
  • Go語(yǔ)言操作MySQL的知識(shí)總結(jié)

    Go語(yǔ)言操作MySQL的知識(shí)總結(jié)

    Go語(yǔ)言中的database/sql包提供了保證SQL或類SQL數(shù)據(jù)庫(kù)的泛用接口,并不提供具體的數(shù)據(jù)庫(kù)驅(qū)動(dòng)。本文介紹了Go語(yǔ)言操作MySQL的相關(guān)知識(shí),感興趣的可以了解一下
    2022-11-11
  • Go依賴注入工具wire的具體使用

    Go依賴注入工具wire的具體使用

    本文主要介紹了Go依賴注入工具wire的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • Go應(yīng)該如何實(shí)現(xiàn)二級(jí)緩存

    Go應(yīng)該如何實(shí)現(xiàn)二級(jí)緩存

    本文主要介紹了Go二級(jí)緩存,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Golang 變量申明的三種方式

    Golang 變量申明的三種方式

    這篇文章主要介紹了Golang 變量申明的三種方式,幫助大家更好的理解和學(xué)習(xí)golang,感興趣的朋友可以了解下
    2020-08-08

最新評(píng)論