go学习记录——第十天

自定义包的目录结构、go install 和 go test

书里为了示范搞了个名为 uc 的简单包,含有一个 UpperCase 函数将字符串的所有字母转换为大写。

自定义包的目录结构

下面给了一个已经弄好的示范( uc 表示通用包名,名字为粗体的代表目录,斜体表示可执行文件。结果上传之后压根没显示,给个链接大家需要的话自己去看uc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/home/user/goprograms
ucmain.go (uc 包主程序)
Makefile (ucmain 的 makefile)
ucmain
src/uc (包含 uc 包的 go 源码)
uc.go
uc_test.go
Makefile (包的 makefile)
uc.a
_obj
uc.a
_test
uc.a
bin (包含最终的执行文件)
ucmain
pkg/linux_amd64
uc.a (包的目标文件)

将项目放在 goprograms 目录下(可以创建一个环境变量 GOPATH ,在 .profile and .bashrc 文件中添加 export GOPATH=/home.user/goprograms )而项目将作为 src 的子目录。 uc 包中的功能在 uc.go中实现。

示例uc.go

1
2
3
4
5
6
package uc
import "strings"

func UpperCase(str string) string {
return strings.ToUpper(str)
}

包通常附带一个或多个测试文件,这里我们创建一个 us_test.go文件

示例test.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package uc
import "testing"

type ucTest struct {
in, out string
}

var ucTests = []ucTest {
ucTest{"abc", "ABC"},
ucTest{"cvo-az", "CVO-AZ"},
ucTest{"Antwerp", "ANTWERP"},
}

func TestUC(t *testing.T) {
for _, ut := range ucTests {
uc := UpperCase(ut.in)
if uc != ut.out {
t.Errorf("UpperCase(%s) = %s, must be %s", ut.in, uc,
ut.out)
}
}
}

通过指令编译并安装包到本地:go install uc ,这回将 uc.a 复制到 pkg/linux_amd64 下面。

另外,使用 make,通过以下内容创建一个包的 Makefile 在 src/uc 目录下

1
2
3
4
5
6
7
include $(GOROOT)/src/Make.inc

TARG=uc
GOFILES=\
uc.go\

include $(GOROOT)/src/Make.pkg

在该目录下的命令行调用:gomake

这将创建一个 _obj 目录并将包编译生成的存档 uc.a 放在该目录下

这个包可以通过 go test 测试

PS:如果当前用户没有足够的权限使用 go install 命令,这种情况下,选择 root 用户 su。确保Go环境变量和Go源码路径也设置给 su,同样也适用于普通用户

接下来创建主程序 ucmain.go :

示例ucmain.go

1
2
3
4
5
6
7
8
9
10
package main
import (
"./src/uc"
"fmt"
)

func main() {
str1 := "USING package uc!"
fmt.Println(uc.UpperCase(str1))
}

然后在这个目录下输入 go install

另外复制 uc.a/home/user/goprograms 目录并创建一个 Makefile 并写入文本:

1
2
3
4
5
6
include $(GOROOT)/src/Make.inc
TARG=ucmain
GOFILES=\
ucmain.go\

include $(GOROOT)/src/Make.cmd

执行 gomake 编译 ucmain.go 生成可执行文件 ucmain

运行 ./ucmain 显示:USING PACKAGE UCI

本地安装包

本地宝在用户目录下,使用给出的目录结构,以下命令用来从源码安装本地包

1
2
3
4
5
go install /home/user/goprograms/src/uc # 编译安装 uc
cd /home/user/goprograms/uc
go install ./uc # 编译安装 uc(和之前的指令一样)
cd ..
go install . # 编译安装 ucmain

安装到 $GOPATH 下:

如果箱安装的包在系统上的其他 Go 程序中使用,则一定要安装到 $GOPATH 下。这样做,在 .profile 和 .bashrc 中设置 export GOPATH=/home/user/goprograms

然后执行 go install uc 将会复制包存档到 $GOPATH/pkg/LINUX_AMD64/uc

现在,uc包可以通过 import "uc"在任何程序中被引用了

依赖系统的代码

在不同的操作系统上运行的程序以不同的代码实现是非常少见的,通常情况下语言和标准库解决了大部分可移植性问题(要是每个程序都得重新写一遍,开发怕是得疯掉)

1
2
3
4
prog1.go
prog1_linux.go
prog1_darwin.go
prog1_windows.go

上面的 prog1.go 定义了不同操作系统通用的接口,并将系统特定的代码写到 prog1_os.go中,对于 Go 工具可以指定 prog1_$GOOS.goprog1_$GOARCH.go 或在平台 Makefile 中:prog1_$(GOOS).go\ or prog1_$(FOARCH).go\

通过Git打包和安装

安装到GitHub

这个不必多说,谁要是说自己不会Git的,直接叉出去乱棍打死。

概括一下就是git init -> git add -> git commit -> git push

从GitHub安装

简单来说就是先go get github.com/***/**

然后机器上就可以使用导入路径import ** URL

抄一下书上写的网站和版本控制系统

  • BitBucket(hg/Git)
  • GitHub(Git)
  • Google Code(hg/Git/svn)
  • Launchpad(bzr)

Go的外部包和项目

现在已经把Go和标准库怎么用了解了个七七八八,但是Go的生态没那么简单,所以在使用前最好查一下第三方包或项目能不能使用(还是版本支不支持,记一下记一下)

Go Walker 支持根据包名在海量数据中查询

目前已经有很多非常好的外部库(好多熟悉的身影啊)

  • MySQL(GoMySQL), PostgreSQL(go-pgsql), MongoDB (mgo, gomongo), CouchDB (couch-go), ODBC (godbcl), Redis (redis.go) and SQLite3 (gosqlite) database drivers
  • SDL bindings
  • Google’s Protocal Buffers(goprotobuf)
  • XML-RPC(go-xmlrpc)
  • Twitter(twitterstream)
  • OAuth libraries(GoAuth)

在 Go 程序中使用外部库

这部分相当于一个比较完整的流程,有点啰嗦我感觉(可能加上我自己的吐槽会更啰嗦,小声哔哔ing)

具体的话就是建立一个 Web 应用和其 Google App Engine 版本,会在第19和21章分别进行具体说明,后续可以回来看(估计书里后续还有URL可以跳转,到时候再看,先打个tag)

当开始一个新项目或增加新功能到现有项目时,可以通过在应用程序中使用已有库来节省开发时间。为了做到这一点,我们就需要理解库的 API,也就是库中的那些方法可以调用,如何调用。可能没有源码,但是作者写的文档一定有记载怎么去使用(文档大法好)

举个例子,我们将Google的 APIurlshortener 编写成一个小程序:可以尝试在http://goo.gl输入一个像"http://www.destandaard.be"这样的URL,就会看到一个像"http://goo.gl/O9SUO"这样更短的URL返回,也就是说,在Twitter之类的服务中,这是非常容易嵌入的(虽然但是我还是没明白这玩意是啥意思,难不成就是借助`goo.gl`去对某个URL进行指引,方便嵌入然后能够在平台查看点击统计和分析相关功能吗?不过我这边看到`goo.gl`现在已经在筹备关闭了,得找其他的短链接服务了,不过逻辑上应该差不多)

Google 让通过使用 Google API Go 客户端服务的开发者开发变得更加简单,Go客户端程序自动生成 Google 库的 JSON 描述,详情在项目页面查看(还没看,先贴上去吧)

下载并安装Go客户端:通过 go install 实现。但是首先要验证环境变量中是否含有 GOPATH 变量,因为外部源码被下载到 $GOPATH/src 目录下并被安装到 $GOPATH/PKG/"machine_arch"/ 目录下。

我们将通过在终端调用以下命令来安装 API

1
go install google.golang.org/api/urlshortener/v1

go install 将下载源码,编译并安装包

使用 urlshortener 服务的 Web 程序:现在我们可以通过导入并赋予别名来使用已安装的包

1
import  "google.golang.org/api/urlshortener/v1"

现在我们来写一个 Web 应用(参考第15章 4-8 节 通过表单实现短地址和长地址的相互转换。我们将使用 template 包并写三个处理函数:root() 函数通过执行表单模板来展示表单,short() 函数将长地址转换为短地址,long() 函数逆向转换。

要调用 urlshortener 接口必须先通过 http 包中的默认客户端创建一个服务实例 urlshortenerSvc

1
urlshortenerSvc, _ := urlshortener.New(http.DefaultClient)

通过调用服务中的 Url.Insert 中的 Do 方法传入包含长地址的 Url 数据结构从而获取短地址:

1
url, _ := urlshortenerSvc.Url.Insert(&urlshortener.Url{LongUrl: longUrl}).Do()

返回 urlId 便是我们需要的短地址。

通过调用服务中的 Url.Get 中的 Do 方法传入包含短地址的 Url 数据结构从而获取长地址:

1
url, error := urlshortenerSvc.Url.Get(shwortUrl).Do()

返回的长地址便是转换前的原始地址。

示例 urlshortener.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package main

import (
"fmt"
"net/http"
"text/template"

"google.golang.org/api/urlshortener/v1"
)
func main() {
http.HandleFunc("/", root)
http.HandleFunc("/short", short)
http.HandleFunc("/long", long)

http.ListenAndServe("localhost:8080", nil)
}
// the template used to show the forms and the results web page to the user
var rootHtmlTmpl = template.Must(template.New("rootHtml").Parse(`
<html><body>
<h1>URL SHORTENER</h1>
{{if .}}{{.}}<br /><br />{{end}}
<form action="/short" type="POST">
Shorten this: <input type="text" name="longUrl" />
<input type="submit" value="Give me the short URL" />
</form>
<br />
<form action="/long" type="POST">
Expand this: http://goo.gl/<input type="text" name="shortUrl" />
<input type="submit" value="Give me the long URL" />
</form>
</body></html>
`))
func root(w http.ResponseWriter, r *http.Request) {
rootHtmlTmpl.Execute(w, nil)
}
func short(w http.ResponseWriter, r *http.Request) {
longUrl := r.FormValue("longUrl")
urlshortenerSvc, _ := urlshortener.New(http.DefaultClient)
url, _ := urlshortenerSvc.Url.Insert(&urlshortener.Url{LongUrl:
longUrl,}).Do()
rootHtmlTmpl.Execute(w, fmt.Sprintf("Shortened version of %s is : %s",
longUrl, url.Id))
}

func long(w http.ResponseWriter, r *http.Request) {
shortUrl := "http://goo.gl/" + r.FormValue("shortUrl")
urlshortenerSvc, _ := urlshortener.New(http.DefaultClient)
url, err := urlshortenerSvc.Url.Get(shortUrl).Do()
if err != nil {
fmt.Println("error: %v", err)
return

}
rootHtmlTmpl.Execute(w, fmt.Sprintf("Longer version of %s is : %s",
shortUrl, url.LongUrl))
}

执行这段代码

1
go run urlshortener.go

通过浏览 http://localhost:8080 的页面来测试

这里书里说并没有进行检测返回的错误状态,但真实的生产环境一定要进行检测(我也觉得,不怕一万就怕万一)

将应用放在 Google App Engine ,我们只需要在之前的代码中做出如下改变

1
2
package main -> package urlshort
func main() -> func init()

创建一个和包同名的目录 urlshort ,并将一下两个安装目录复制到这个目录:

1
2
google.golang.org/api/urlshortener
google.golang.org/api/googleapi

此外还要配置下配置文件 app.yaml,内容如下:

1
2
3
4
5
6
7
application: urlshort
version: 0-1-test
runtime: go
api_version: 3
handlers:
- url: /.*
script: _go_app

现在可以到项目目录并在终端运行: dev_appserver.py urlshort

然后在浏览器打开 http://localhost:8080


go学习记录——第十天
https://www.lx02918.ltd/2024/11/26/go-study-tenth-day/
作者
Seth
发布于
2024年11月26日
许可协议