>  기사  >  백엔드 개발  >  Go를 사용하여 CLI 프로그램 빌드

Go를 사용하여 CLI 프로그램 빌드

Guanhui
Guanhui앞으로
2020-06-12 18:28:173614검색

Go를 사용하여 CLI 프로그램 빌드

Go 구문을 계속해서 연습했을 수도 있지만 직접 애플리케이션을 구축하지 않는 한 Go로 애플리케이션을 작성하는 실제 느낌을 깨닫지 못할 것입니다.

이 블로그 게시물에서는 CLI 애플리케이션을 구축할 것입니다. Go, go-grab-xkcd라고 부르겠습니다. 이 애플리케이션은 XKCD에서 만화를 가져오고 명령줄 매개변수를 통해 다양한 작업 옵션을 제공합니다.

우리는 Go 표준 라이브러리를 사용하여 외부 종속성을 사용하지 않고 전체 애플리케이션을 구축할 것입니다.

이 애플리케이션의 아이디어는 다소 어리석게 보일 수 있지만, Google에 인수되는 것을 원하지 않고 Go에서 프로덕션 수준(일종의) 코드 작성을 연습하는 것이 목적입니다.

마지막에 추가 보너스

참고: 이 글에서는 독자가 이미 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 응답입니다. comic.go의 모델 패키지에 ComicResponse

{
  "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": ""
}
라는 구조체를 생성하세요

JSON-to-Go 도구를 사용하여 JSON에서 구조체를 자동으로 생성할 수 있습니다.

그런데 다음에서 데이터를 출력하는 데 사용할 다른 구조체를 생성하세요.

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"`
}

ComicResponse 구조에 다음 두 가지 메소드를 추가합니다

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

그런 다음 Comic 구조에 다음 두 가지 메소드를 추가합니다

// 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,
    }
}

3: xkcd 클라이언트를 설정하여 요청을 시작하고 응답을 구문 분석한 후 저장합니다. disk

클라이언트 패키지 xkcd.go 파일에서 생성됩니다.

먼저 ComicNumber라는 사용자 정의 유형을 정의하고 데이터 유형은 int입니다.

type ComicNumber int

상수 정의

// 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)
}

XKCDClient 구조를 생성합니다. API에 요청합니다.

const (
    // xkcd 的 BaseURL
    BaseURL string = "https://xkcd.com"
    // DefaultClientTimeout 是取消请求之前要等待的时间
    DefaultClientTimeout time.Duration = 30 * time.Second
    // 根据 xkcd API, LatestComic 是最新的漫画编号
    LatestComic ComicNumber = 0
)

Read 명령줄 매개변수

Instantiate XKCDClient

XKCDClient를 사용하여 API에서 데이터를 가져옵니다

Output

Read 명령줄 매개변수

// XKCDClient 是 XKCD 的客户端结构体
type XKCDClient struct {
    client  *http.Client
    baseURL string
}
// NewXKCDClient 创建一个新的 XKCDClient
func NewXKCDClient() *XKCDClient {
    return &XKCDClient{
        client: &http.Client{
            Timeout: DefaultClientTimeout,
        },
        baseURL: BaseURL,
    }
}

flag.Parse에 다음 4가지 메서드를 추가합니다. ()

XKCDClient 인스턴스화

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

API에서 XKCDClient를 사용하여 데이터 가져오기

// 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
}

output

// 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
}

프로그램은 다음과 같이 실행됩니다

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
}

또는 노트북에서 바이너리 실행 파일로 빌드하여 실행하세요

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",
)

전체 소스 코드는 다음과 같습니다. 이 Github 저장소에서 찾을 수 있습니다 - go-grab-xkcd

추가 보너스

이 간단한 쉘 마법 도구를 사용하여 여러 만화를 순서대로 다운로드할 수 있습니다

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

위의 쉘 코드는 단순히 go-grab-xkcd 명령을 호출합니다 for 루프에서는 xkcd가 정수 시퀀스를 사용하므로 i 값을 만화 번호/ID로 만화 번호로 바꿉니다.

권장 튜토리얼: "

PHP

" "

Go Tutorial

"

위 내용은 Go를 사용하여 CLI 프로그램 빌드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 learnku.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
이전 기사:Go String 분석다음 기사:Go String 분석