Go を使用して CLI プログラムを構築する

Guanhui
リリース: 2020-06-13 09:03:28
転載
3613 人が閲覧しました

Go を使用して CLI プログラムを構築する

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 サイトの他の関連記事を参照してください。

関連ラベル:
ソース:learnku.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート