通过构建CLI应用程序深入了解Go

2020-05-27 08:52:32

您已经了解了GO语法,并逐个进行了练习,但是,除非您构建了一个应用程序,否则在GO中编写应用程序会让您感到不舒服。

在这篇博客文章中,我们将在GO中构建一个CLI应用程序,我们将其称为go-Grab-xkc.该应用程序从XKCD获取漫画,并通过命令行参数为您提供各种选项。

我们将不使用外部依赖项,并且将只使用Go标准库构建整个应用程序。

这个应用程序的想法看起来很愚蠢,但其目的是在Go中轻松地编写产品(某种)代码,而不是被Google收购。

注意:这篇文章假设读者熟悉围棋语法和术语,介于初学者和中级之间。

$go-Grab-xkcd--help Go-Grab-xkcd的用法:-n int Comic Number to Fetch(默认最新)-o String打印输出格式:text/json(默认值";text";)-s将图像保存到当前目录-t int客户端超时(以秒为单位)(默认值30)。

$go-grab-xkcd-n 323标题:鲍尔默巅峰漫画编号:323日期:1-10-2007描述:苹果使用自动烈性酒IV。图片:https://imgs.xkcd.com/comics/ballmer_peak.png。

$go-Grab-xkcd-n 323-o json{";Title";:";Ballmer Peak";,";:323,";Date";:";1-10-2007";,";Description";:";:";Apple使用自动烈性酒IV.";,";image";:";https://imgs.xkcd.com/comics/ballmer_peak.png";}

您可以通过下载并运行适用于您计算机的应用程序来尝试其余选项。

本教程结束后,您将熟悉以下主题-。

$TREE go-Grab-xkcdgo-Grab-xkcd├──Client│└──xkcd.go└──model└──comic.go├──main.go└──go.mod。

xkcd.go-用于对API进行HTTP调用、解析响应并保存到磁盘的xkcd客户端。

xkcd非常棒,您不需要任何注册或访问密钥就可以使用他们的API。打开xkcd API“文档”,您会发现有2个端点-。

{";数字";:2311,";月";:";5";,";天";:";25";,";年份";:";2020";,";标题";:";置信区间";,";Alt";:";最糟糕的部分是';的毫西格玛间隔。";,";img";:";https://imgs.xkcd.com/comics/confidence_interval.png";,";SAFE_TITLE&34;:";置信区间";,";链接";:";";,";新闻";:";";,";文字记录";:";";}。

基于上面的JSON响应,我们在comic.go模型包中创建了一个名为ComicResponse的结构。

输入ComicResponse struct{月字符串`json:";月";`num int`json:";num";`链接字符串`json:";link";`年份字符串`json:";年";`新闻字符串`json:";news";`安全标题字符串`json:";Safe_Title";`文本字符串`json:&&。img";`标题字符串`json:";title";`日字符串`json:";day";`}

类型Comic struct{title string`json:";title";`number int`json:";number";`date string`json:";date";`description string`json:";description";`Image string`json:";image";`}。

//FormattedDate将各个Date元素格式化为单个字符串函数(Cr ComicResponse)FormattedDate()string{return fmt。Sprintf(";%s-%s-%s";,cr。日期,cr.。月,cr.。年份)}。

//Comic将我们从API接收到的ComicResponse转换为应用程序的输出格式Comic func(Cr ComicResponse)Comic()Comic{return Comic{title:cr。标题,编号:cr。编号,日期:Cr。FormattedDate(),描述:cr。Alt,图像:Cr。img,}}。

//PrettyString创建Comic的漂亮字符串,我们将使用该字符串作为输出函数(C Comic)PrettyString()string{p:=fmt。Sprintf(";标题:%s\n漫画编号:%d\n日期:%s\n描述:%s\n图像:%s\n";,c..。标题,c。编号,c。日期,c.。描述,c.。图像)返回p}。

//JSON将Comic结构转换为JSON,我们将使用JSON字符串作为输出函数(C Comic)JSON()字符串{cJSON,err:=json。Marshal(C)if err!=nil{return";";}return string(CJSON)}。

const(//xkcd BaseURL String=";https://xkcd.com";//DefaultClientTimeout是取消请求前等待的时间DefaultClientTimeout时间。持续时间=30*时间。Second//LatestComic是xkcd接口LatestComic ComicNumber=0中最新的漫画号。

//XKCDClient是XKCD类型XKCDClient struct{client*http.。client baseURL string}//NewXKCDClient创建一个新的XKCDClient函数NewXKCDClient()*XKCDClient{return&;XKCDClient{client:&;http。客户端{timeout:DefaultClientTimeout,},baseURL:BaseURL,}}。

//FETCH按照提供的漫画号函数FUNC(HC*XKCDClient)FETCH(n ComicNumber,save bool)(model.。漫画,错误){对应,错误:=hc。客户。GET(HC.。buildURL(N))如果err!=nil{返回模型。漫画{},错误}分别推迟。身体。Close()var comicResp模型。如果err:=json,则返回ComicResponse。NewDecoder(分别为。身体)。DECODE(&;comicResp);err!=nil{返回模型。comic{},err}if save{if err:=hc。SaveToDisk(comicResp.。img,";.";);err!=nil{fmt.。Println(";无法保存图像!";)}}返回comicResp。comic(),无}

//SaveToDisk下载并保存漫画本地函数(HC*XKCDClient)SaveToDisk(url,savePath string)error{resp,err:=http。如果err!=nil{return err}延迟响应,则GET(Url)。身体。Close()disSavePath,_:=文件路径。ABS(SavePath)filePath:=fmt。Sprintf(";%s/%s";,disSavePath,路径。base(Url))文件,err:=os。如果err!=nil{return err}延迟文件,则创建(FilePath)。CLOSE()_,ERR=io。复制(文件,分别。正文)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)}返回finalURL}。

漫画号:=旗帜。int(";n";,int(客户端。LatestComic),";要获取的漫画号(默认最新)";,)clientTimeout:=flag。Int64(";t";,int64(客户端。DefaultClientTimeout。秒()),";客户端超时(秒)";,)saveImage:=flag。bool(";s";,false,";将图像保存到当前目录";,)outputType:=flag。字符串(";o";,";text";,";打印输出格式:text/json";,)标志。parse()。

上面的shell代码简单地调用了for循环中的go-Grab-xkcd命令,由于xkcd使用序列整数作为漫画号/ID,因此i值被替换为漫画号。