站長資訊網
        最全最豐富的資訊網站

        使用 Go 來構建一個 CLI 程序

        使用 Go 來構建一個 CLI 程序

        您或許已經圍繞 Go 語法進行了一次又一次的練習,但是除非您自己構建了一個應用程序,不然的話是體會不到用 Go 編寫應用程序的真實觸感的.

        在這篇博文中,我們將用 Go 構建一個 CLI 應用程序,我們暫且把它叫做 go-grab-xkcd. 該應用程序從 XKCD 拉取漫畫并通過命令行參數為您提供各種操作選項.

        我們將僅使用 Go 標準庫構建整個應用程序而不使用外部依賴.

        這個應用程序的想法或許看起來有點秀逗,但目的是實踐用 Go 編寫生產級別的 (某種) 代碼而不是想被 Google 收購.

        最后還有一個額外獎勵

        注意:本文假設讀者已熟悉 Go 語法和術語,并處于初學者和中級之間.

        讓我們先來運行一下這個應用程序,然后再進行操作

        $ go-grab-xkcd --help Usage of go-grab-xkcd:   -n int         Comic number to fetch (default latest)   -o string         Print output in format: text/json (default "text")   -s    Save image to current directory   -t int         Client timeout in seconds (default 30) $ go-grab-xkcd -n 323 Title: Ballmer Peak Comic No: 323 Date: 1-10-2007 Description: Apple uses automated schnapps IVs. Image: https://imgs.xkcd.com/comics/ballmer_peak.png $ go-grab-xkcd -n 323 -o json {   "title": "Ballmer Peak",   "number": 323,   "date": "1-10-2007",   "description": "Apple uses automated schnapps IVs.",   "image": "https://imgs.xkcd.com/comics/ballmer_peak.png" }

        你可以通過下載并運行計算機上的應用程序來嘗試其他選項.

        本教程結束后你將熟悉以下主題內容:

        接收命令行參數

        JSON 和 Go 結構體之間的相互轉換

        進行 API 調用

        創建文件 (從網絡上下載并保存)

        字符串操作

        以下是項目結構

        $ tree go-grab-xkcd go-grab-xkcd ├── client │   └── xkcd.go └── model     └── comic.go ├── main.go └── go.mod go.mod - Go Modules file used in Go for package management main.go - Main entrypoint of the application comic.go - Go representation of the data as a struct and operations on it xkcd.go - xkcd client for making HTTP calls to the API, parsing response and saving to disk

        1: 初始化項目

        創建一個 go.mod 文件 –

        $ go mod init

        這將會有助于你進行包管理 (思考 JS 中的 package.json 文件)。

        2: xkcd API

        xkcd 是令人稱贊的,您不需要任何注冊或訪問密鑰就可以使用它們的 API。 打開 xkcd API “文檔” 您將會發現有兩個端點 –

        http://xkcd.com/info.0.json – 獲取最新漫畫

        http://xkcd.com/614/info.0.json – 通過漫畫編號獲取指定的漫畫

        以下是這些端點的 JSON 響應 –

        {   "num": 2311,   "month": "5",   "day": "25",   "year": "2020",   "title": "Confidence Interval",   "alt": "The worst part is that's the millisigma interval.",   "img": "https://imgs.xkcd.com/comics/confidence_interval.png",   "safe_title": "Confidence Interval",   "link": "",   "news": "",   "transcript": "" }

        文章相關 xkcd

        2: 為漫畫創建模型

        根據上述 JSON 響應,我們在 model 包中的 comic.go 中創建一個叫做 ComicResponse 的 struct

        type ComicResponse struct {     Month      string `json:"month"`     Num        int    `json:"num"`     Link       string `json:"link"`     Year       string `json:"year"`     News       string `json:"news"`     SafeTitle  string `json:"safe_title"`     Transcript string `json:"transcript"`     Alt        string `json:"alt"`     Img        string `json:"img"`     Title      string `json:"title"`     Day        string `json:"day"` }

        您可以使用 JSON-to-Go 工具從 JSON 自動生成結構體.

        順便創建另一個結構體,該結構體將用于從我們的應用程序輸出數據.

        type Comic struct {     Title       string `json:"title"`     Number      int    `json:"number"`     Date        string `json:"date"`     Description string `json:"description"`     Image       string `json:"image"` }

        將以下兩種方法添加到 ComicResponse 結構體

        // FormattedDate 函數將格式化日期元素為一個字符串 func (cr ComicResponse) FormattedDate() string {     return fmt.Sprintf("%s-%s-%s", cr.Day, cr.Month, cr.Year) } // Comic 函數將從 API 接收到的 ComicResponse 轉換為應用程序的輸出格式, Comic 結構體 func (cr ComicResponse) Comic() Comic {     return Comic{         Title:       cr.Title,         Number:      cr.Num,         Date:        cr.FormattedDate(),         Description: cr.Alt,         Image:       cr.Img,     } }

        然后將以下兩種方法添加到 Comic 結構體

        // PrettyString 函數創建一個漂亮的 Comic 字符串并用于輸出 func (c Comic) PrettyString() string {     p := fmt.Sprintf(         "Title: %snComic No: %dnDate: %snDescription: %snImage: %sn",         c.Title, c.Number, c.Date, c.Description, c.Image)     return p } // JSON 函數將 Comic 結構體轉換為 JSON, 我們將使用 JSON 字符串作為輸出內容 func (c Comic) JSON() string {     cJSON, err := json.Marshal(c)     if err != nil {         return ""     }     return string(cJSON) }

        3: 設置 xkcd 客戶端發起請求,解析響應并保存到磁盤

        在 client 包中創建 xkcd.go 文件.

        首先定義一個叫做 ComicNumber 自定義類型,數據類型為 int

        type ComicNumber int

        定義常量

        const (     // xkcd 的 BaseURL     BaseURL string = "https://xkcd.com"     // DefaultClientTimeout 是取消請求之前要等待的時間     DefaultClientTimeout time.Duration = 30 * time.Second     // 根據 xkcd API, LatestComic 是最新的漫畫編號     LatestComic ComicNumber = 0 )

        創建一個結構體 XKCDClient, 它將用于向 API 發出請求.

        // XKCDClient 是 XKCD 的客戶端結構體 type XKCDClient struct {     client  *http.Client     baseURL string } // NewXKCDClient 創建一個新的 XKCDClient func NewXKCDClient() *XKCDClient {     return &XKCDClient{         client: &http.Client{             Timeout: DefaultClientTimeout,         },         baseURL: BaseURL,     } }

        添加以下 4 種方法到 XKCDClient

        SetTimeout()

        // SetTimeout 重寫了默認的 ClientTimeout func (hc *XKCDClient) SetTimeout(d time.Duration) {     hc.client.Timeout = d }

        Fetch()

        // Fetch 根據提供的漫畫編號檢索漫畫 func (hc *XKCDClient) Fetch(n ComicNumber, save bool) (model.Comic, error) {     resp, err := hc.client.Get(hc.buildURL(n))     if err != nil {         return model.Comic{}, err     }     defer resp.Body.Close()     var comicResp model.ComicResponse     if err := json.NewDecoder(resp.Body).Decode(&comicResp); err != nil {         return model.Comic{}, err     }     if save {         if err := hc.SaveToDisk(comicResp.Img, "."); err != nil {             fmt.Println("Failed to save image!")         }     }     return comicResp.Comic(), nil }

        SaveToDisk()

        // SaveToDisk 下載并保存漫畫到本地磁盤 func (hc *XKCDClient) SaveToDisk(url, savePath string) error {     resp, err := http.Get(url)     if err != nil {         return err     }     defer resp.Body.Close()     absSavePath, _ := filepath.Abs(savePath)     filePath := fmt.Sprintf("%s/%s", absSavePath, path.Base(url))     file, err := os.Create(filePath)     if err != nil {         return err     }     defer file.Close()     _, err = io.Copy(file, resp.Body)     if err != nil {         return err     }     return nil }

        buildURL()

        func (hc *XKCDClient) buildURL(n ComicNumber) string {     var finalURL string     if n == LatestComic {         finalURL = fmt.Sprintf("%s/info.0.json", hc.baseURL)     } else {         finalURL = fmt.Sprintf("%s/%d/info.0.json", hc.baseURL, n)     }     return finalURL }

        4: 連接所有

        在 main() 函數內部我們鏈接了所有內容

        讀取命令行參數

        實例化 XKCDClient

        使用 XKCDClient 從 API 拉取數據

        輸出

        讀取命令行參數

        comicNo := flag.Int(     "n", int(client.LatestComic), "Comic number to fetch (default latest)", ) clientTimeout := flag.Int64(     "t", int64(client.DefaultClientTimeout.Seconds()), "Client timeout in seconds", ) saveImage := flag.Bool(     "s", false, "Save image to current directory", ) outputType := flag.String(     "o", "text", "Print output in format: text/json", )

        flag.Parse()

        實例化 XKCDClient

        xkcdClient := client.NewXKCDClient() xkcdClient.SetTimeout(time.Duration(*clientTimeout) * time.Second)

        使用 XKCDClient 從 API 拉取數據

        comic, err := xkcdClient.Fetch(client.ComicNumber(*comicNo), *saveImage) if err != nil {     log.Println(err) }

        輸出

        if *outputType == "json" {     fmt.Println(comic.JSON()) } else {     fmt.Println(comic.PrettyString()) }

        程序運行如下

        $ go run main.go -n 323 -o json

        或者將其構建為你的筆記本電腦的二進制可執行文件并運行它

        $ go build . $ ./go-grab-xkcd -n 323 -s -o json

        可以在這個 Github 倉庫找到完整的源代碼 – go-grab-xkcd

        額外獎勵

        通過使用這個簡單的 shell 魔術工具可以依次下載多個漫畫

        $ for i in {1..10}; do ./go-grab-xkcd -n $i -s; done;

        上面的 shell 代碼簡單地在 for 循環中調用 go-grab-xkcd 命令,由于 xkcd 使用序列整數,因此將 i 值替換為漫畫編號作為漫畫編號 / ID.

        推薦教程:《PHP》

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 国产精品亚洲一区二区三区在线| 久久国产精品77777| 亚洲精品视频免费观看| 国产精品久久久久久吹潮| 精品亚洲欧美无人区乱码 | 国产免费久久精品99久久| 热re99久久6国产精品免费| 精品国产免费一区二区三区| 九九热这里只有在线精品视| 欧美精品VIDEOSSEX少妇| 久久久亚洲精品蜜桃臀| 伊人久久大香线蕉精品| 高清在线亚洲精品国产二区| 精品一区二区三区自拍图片区| 免费看一级毛片在线观看精品视频 | 国产精品臀控福利在线观看| 精品调教CHINESEGAY| 亚洲国产精品久久久天堂| 日韩精品免费一线在线观看| 精品国产一区二区三区久久蜜臀| 9999国产精品欧美久久久久久| 精品久久一区二区| 精品福利一区二区三| 国产精品青草久久久久婷婷| 东京热TOKYO综合久久精品| 久久久无码精品亚洲日韩按摩 | 国产99久久久国产精品~~牛| 国产精品手机在线| 韩国精品欧美一区二区三区| 国产精品美女久久久| 99精品久久精品| 69久久夜色精品国产69| 国内精品久久久久影院优| 久久国产精品99国产精| 国产精品高清一区二区三区| 国99精品无码一区二区三区| 91精品国产综合久久婷婷| 国产亚洲欧洲精品| 9191精品国产免费久久| 国产精品麻豆VA在线播放| 精品久久久久久国产三级|