Go 構文を何度も練習したことがあるかもしれませんが、自分でアプリケーションを構築しない限り、Go でアプリケーションを作成する本当の感覚を体験したことはありません。このブログ投稿では、Go で CLI アプリケーションを構築します。go-grab-xkcd と呼びます。アプリケーションは XKCD からコミックを取得し、コマンド ライン パラメーターを通じてコミックを提供します。さまざまな操作オプションを提供します。
We外部の依存関係を使用せず、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 の「ドキュメント」を開くと、2 つのエンドポイントがあることがわかります -
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 レスポンスに従って、モデル パッケージの comic.go に ComicResponse という構造体を作成します
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"` }
次の 2 つのメソッドを 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, } }
次に、次の 2 つのメソッドをコミック構造に追加します
// PrettyString 函数创建一个漂亮的 Comic 字符串并用于输出 func (c Comic) PrettyString() string { p := fmt.Sprintf( "Title: %s\nComic No: %d\nDate: %s\nDescription: %s\nImage: %s\n", 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 クライアントを設定してリクエストを開始し、レスポンスを解析してディスクに保存します
xkcd を作成しますgo file.
最初に 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 )
API へのリクエストを行うために使用される構造体 XKCDClient を作成します。
// 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
## にあります。#追加のボーナス
このシンプルなシェル マジック ツールを使用すると、複数のコミックを順番にダウンロードできます
$ for i in {1..10}; do ./go-grab-xkcd -n $i -s; done;上記のシェル コードは、単に for で go-grab-xkcd を呼び出します。ループ コマンドでは、xkcd はシーケンス整数を使用するため、i の値をコミック番号/ID としてコミック番号に置き換えます。 推奨チュートリアル: "
PHP
" "Go Tutorial"
以上がGo を使用して CLI プログラムを構築するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。