通向Golang的捷径【9. 包】

9.1 标准库

Go 语言发行版中, 包含了 150 个标准包, 其中包含大部分的基本功能, 比如 fmt,os 等, 这些包也被称为标准库, 除了一些底层包之外, 其他大部分包的文档, 都可在页面http://golang.org/pkg/中找到.

在本书的大部分示例中, 都会使用到标准包, 并且附录中将包含标准包的索引表和相关用法, 本章将描述一些包函数的用法, 但是并不会讨论这些包函数的内部细节.

• unsafe:
可实现 Go 语言中类型安全的一些命令, 这些命令并不会在普通程序中实现, 而是常用于与 C/C++ 的接口.

• syscall ⊕ os ⊕ os/exec:
▶ os:
可提供一个与平台无关的接口, 以实现与本地操作系统的关联, 基于类 Unix 系统, 完成了它们的设计, 同时它们隐藏了不同操作系统之间的差异, 以使文件以及其他操作系统对象, 可实现一致性的处理.
▶os/exec:
用于运行本地操作系统所包含的一些命令或程序.
▶ syscall:
这是一个底层包, 可为操作系统调用, 提供一个基本接口.

以下 Go 代码可实现 Linux 系统的重新启动命令 (reboot):

例 9.1 reboot.go

在这里插入图片描述
•archive/tar:
archive/zip-compress:
用于压缩和解压文件.

• fmt ⊕ io ⊕ bufio ⊕ path/filepath ⊕ flag:
▶ fmt: 用于格式化的输入和输出.
▶ io: 用于基本的输入和输出, 通常用于操作系统函数的封装器.
▶ bufio: 用于缓冲输入和输出的封装.
▶ path/filepath: 用于提供操作系统的文件名路径.
▶ flag: 用于提供命令行的选项参数.

• strings ⊕ strconv ⊕ unicode ⊕ regexp ⊕ bytes ⊕ index/suffixarray:
▶ strings: 用于处理字符串.
▶ strconv: 用于基本数据类型的转换.
▶ unicode: 用于处理 Unicode 字符.
▶ regexp: 用于复杂字符串的正则匹配.
▶ bytes: 用于处理字节 slice.
▶ index/suffixarray: 可实现字符串的快速检索.

• math ⊕ math/cmath ⊕ math/rand ⊕ sort ⊕ math/big:
▶ math: 可提供基本的数学常量和运算函数.
▶ math/cmath: 用于复数.
▶ math/rand: 包含了伪随机数发生器.
▶ sort: 用于数组和自定义集合的排序.
▶ math/big: 包含了大型整数和有理数的不同精度的运算函数

• container/list ⊕ container/ring ⊕ container/heap:
▶ container/list: 双链列表的处理.

检索链表指针 (*List)l:

在这里插入图片描述
▶ container/ring: 循环列表的处理.
▶ container/heap: 内存堆的处理.

• time ⊕ log:
▶ time: 时间和日期的处理函数.
▶ log: 运行程序的日志函数, 在后续小节中, 将给出相关示例.

• encoding/json ⊕ encoding/xml ⊕ text/template:
▶ encoding/json: 基于 JSON 格式, 实现读取 (解码) 和写入 (编码).
▶ encoding/xml: 一个简单的 XML 1.0 解析器,12.9-10 节将给出 json 和 xml 示例.
▶ text/template: 可创建一个数据驱动的模板, 以生成文本和数据的混合输出, 例如 HTML, 参见 15.7节.

• net ⊕ net/http ⊕ html(参见第 15 章)
▶ net: 处理网络数据的基本函数.
▶ net/http: 可解析 http 请求/应答的函数, 并能提供扩展的 http 服务器和一个基础客户端.
▶ html: HTML 5 解析器.

• crypto ⊕ encoding ⊕ hash ⊕ …:
实现数据加密和解密的多个包.

• runtime ⊕ reflect:
▶ runtime: Go 运行时状态的交互操作, 比如垃圾收集和并发协程.
▶ reflect: 实现运行时状态的自检, 允许程序使用任意类型的变量.

exp 包给出了一些实验性的包, 也就是准备投入实用的一些新包, 如果这些包能够稳定工作, 将在下一个稳定版本中, 加入这些实验包, 如果之前的版本中已经包含, 可移除之前的旧包, 同时弃用的包也会给出一个循环利用的机制. 在 Go 1 版本中, 未包含旧包和 exp 包.

9.2 regexp 包

页面http://en.wikipedia.org/wiki/Regular_expression 中, 给出了正则表达式和相关语法, 以下程序将在字符串 searchIn 中, 检索与模板 pat 相匹配的字串.
在这里插入图片描述
为了实现更多的功能, 首先必须创建一个模板对象, 这可在 Compile 函数中完成, 之后可基于模板, 实现匹配,查找和替换功能.

例 9.2 pattern.go

在这里插入图片描述
在这里插入图片描述
Compile 函数也可返回一个错误码, 如果模板是一个有效的正则表达式, 则可安全忽略 Compile 函数返回的错误码, 而用户输入的正则表达式, 可预先进行必要的解析检查. 在上述示例中, 可使用 MustCompile 函数, 它与 Compile 函数的功能类似, 当匹配模板不是一个有效正则表达式,MustCompile 函数可终止程序执行, 并发送一个错误消息, 参见 13.2 节.

9.3 sync 包

复杂程序的不同部分可实现同步 (并发) 执行, 通常情况下, 是在操作系统的不同线程中, 执行程序的不同部分,如果程序的不同部分共享了同一变量, 将产生以下问题, 共享变量的更新次序无法预知, 因此将产生不可预知的共享变量值, 这被称为竞争条件, 即更新共享变量的线程之间, 将产生竞争, 如果希望程序能够稳定运行, 竞争条件是不可接受的, 以下将给出上述问题的解决方案.

经典的解决方案是, 一次只能有一个线程, 可修改共享变量, 当线程准备修改共享变量时, 首先将锁定共享变量(这被称为临界区), 这时其他线程无法修改共享变量, 当线程完成修改后, 将解锁临界区, 这时其他线程可尝试锁定共享变量.

之前学过的 map 类型并未包含内部的锁定条件, 以获取上述的操作结果 (这也是出于性能的需求), 因此 map类型无法提供线程安全性, 当一个共享 map 类型面对并发访问时, 无法实现正确的访问方式.

在 Go 语言中, 可使用 sync 包的 Mutex 变量, 作为锁定条件, sync 包可实现同步处理, 也就是实现线程的同步, 或是共享变量的有序更新. sync.Mutex 是一个互斥锁, 它可守护代码临界区的入口, 同时可保证在任意时刻下, 只有一个线程可进入临界区. 如果 Info 是一个包含锁定标记的共享变量类型, 以下代码将使用了一个互斥, 来保护对应的共享变量:
在这里插入图片描述
而修改共享变量的函数如下:
在这里插入图片描述
上述方法也可用于共享一个缓冲类型, 也就是在更新 SyncedBuffer(共享缓冲) 之前, 先锁定互斥标记:
在这里插入图片描述
在 sync 包中, 还包含了 RWMutex, 这个锁定标记允许多个线程调用 RLock() 进行读取, 但只有一个线程可进行写入, 如果使用了 Lock(), 临界区将锁定, 并等待写入, 这与互斥 (Mutex) 功能相似, 同时还包含一个易用函数 once.Do(call), 其中 once 是一个 Once 类型的变量, 该函数可保证只被调用一次, 而且不在意有多少个 once的 Do(call) 被调用.

最简单的方法是采用 sync 包提供的锁定标记, 来保证任意时刻下, 只有一个线程可返回共享变量或 map, 如果因线程过多而造成同步切换的速度太慢, 或是引发了其他问题, 这时推荐使用并发协程或是并发通道, 这也是编写并发应用时,Go 语言的推荐方法, 在第 14 章中, 将比较这两种方法的优劣.

9.4 数学包

我们知道程序执行的运算结果有时并不精确, 如果使用 float64 类型实现浮点数的运算, 其结果的精度可达到15 个有效数字 (十进制) 以上, 这对于大多数任务来说已经足够了, 当进行 int64 或 uint64 类型的运算时, 可使用一种方法来降低运算量, 也就是在不要求精度的情况下, 使用 float32 或 float64, 而在一般情况下, 我们并不会使用浮点数, 因为浮点数只是一个近似值.

为了实现整型大值的高精度运算,Go 语言提供了 big 包, 它包含在 math 包中, big.Int 可表示整型,big.Rat 可表示有理数 (可使用分数表示的数, 比如 2/5 或 3.1416, 而无理数只能使用 e 或 π 表示), 上述类型可保存任意数字位, 只受限于本地机的内存容量, 但会造成内存用量和处理开销的增加, 因此这类处理的速度将低于普通整型的处理.

big 整型需使用 big.NewInt(n) 函数进行创建, 其中的 n 为 int64 类型, 一个 big 有理数将使用big.NewRat(n,d) 创建, 其中 n 为分子,d 为分母, 同时也将得到一个 int64 类型的数值, 由于 Go 语言不支持操作符重载,因此 big 类型的所有方法都是自己的名称, 比如 Add() 和 Mul(), 这些方法 (参见 10.6 节) 都给出了一个接收器, 它可接受整型或有理数的输入, 在大多数情况下, 都可对接收器进行修改, 以返回所需的结果, 同时这些方法的处理相当紧凑, 并会将结果保存在内存, 因为不会创建一个 big.Int 类型的临时变量, 用于保存中间结果.

例 9.3 big.go

在这里插入图片描述

9.5 自定义包和可见性

包是 Go 语言组织代码和编译代码的基础单元, 包的基本信息可参考 4.2 节, 最关键的内容就是可见性规则,这里将自定义一个包, 同时给出包的用法, 在下一节中, 还将继续介绍一些标准包, 自定义包是指自行编写一个包, 或是对标准包进行扩展.

在编写自定义包时, 必须使用简短的小写文件名 (在文件名中不能使用下划线 _), 以下将给出包之间的相互查找, 以及对应的可见性规则.

以下代码定义了一个自定义包 pack1, 当它引入应用程序, 而应用程序完成编译和链接后, 将会得到一个 pack1.a文件, 该文件将保存在项目路径下的 pack1 目录中, 同时链接器会将包生成的目标代码, 链接到应用程序的目标代码中.

例 9.4 pack1.go

在这里插入图片描述
自定义包 pack1 可导出一个 int 变量 Pack1Int 和一个函数 ReturnStr(可返回一个字符串类型), 上述代码是无法执行的, 因为缺少一个 main 函数. 在应用程序的代码中, 需使用以下语句, 导入自定义包 pack1:

在这里插入图片描述
上述代码中, 自定义包需给出基于项目路径的相对路径.

例 9.5 pack1.go

在这里插入图片描述
首先./pack1/pack1 的导入格式并不值得推荐, 在上述代码中, 注释了最后一行代码, 如果尝试访问一个未导入的变量或函数, 将无法实现编译, 并产生一个错误:
在这里插入图片描述
在应用程序编译之前, 引入应用程序的包必须首先编译, 从 pack1 包中导入的每个元素, 在使用时必须添加包名标识符, 如 pack1.Pack1Int.

包与子目录的关系, 每个包 (从属于该包的所有 go 文件) 都将放在同名的子目录中, 因此不同的包将放入不同的子目录中, 顶层目录为项目的主目录.
在这里插入图片描述
如果在导入语句中, 使用了. 作为假名, 这意味着在使用包的导入元素时, 无须添加包名标识符, 如test1 = ReturnStr(), 而这类导入方式, 通常用于测试.
在这里插入图片描述
上述导入方式将存在副作用, 即包的 init 函数将被执行, 同时全局变量也将被初始化, 这将污染主文件的名字空间.

扩展包的导入

如果在应用程序中, 需要一个或多个扩展包时, 则需要使用 go install 命令 (参见 9.7 节), 安装这些扩展包. 假定需要一个包, 它放置在http://codesite.ext/author/goExample/goex 页面上, 同时 codesite 可能是 google-code,github,bitbucket,launchpad 或其他源码仓库, 而 ext 可能是.com 或.org, 而 goex 则是包名.

使用go install codesite.ext/author/goExample/goex 命令, 可安装所需的包, 这时codesite.ext/author/goExample/goex 将映射到$GOROOT/src/路径下, 一旦完成安装, 可使用以下语句进行导入:
在这里插入图片描述
以上给出的网页名称, 可从项目的根目录开始逐级查找. 从http://golang.org/cmd/goinstall/页面, 可查找到go install 的相关文档, 其中可找到在路径导入中, 使用源码仓库网址的大量示例.

包的初始化

应用程序的执行将从包的导入开始, 之后是 main 包的初始化, 然后将调用 main() 函数.

如果包未导入其他包, 将初始化所有包变量 (分配初值), 并执行包代码定义的 init 函数, 一个包可能包含多个init() 函数, 同时这多个 init() 函数可能包含在一个源文件中, 因此它们的执行并无一个预定的次序, 所以推荐, 所有的初始操作最好能在同一个包中实现.

在包初始化之前, 必须首先初始化导入包 (main 包是个例外), 在应用程序的执行中, 一个包的初始化只能出现一次.

包的构建和安装

在 Linux 和 OS X 系统中, 包的构建和安装需使用 Makefile 脚本:
在这里插入图片描述
使用chmod 777 ./Makefile 命令后, 执行 make, 实现包的构建和安装. 在 include 语句中, 包含了本机架构的自动检测, 以及编译器和链接器的正确配置. 在命令行或 gomake 工具中, 可执行 make 命令, 同时在 make 命令中, 可增加静态库 pack1.a.

go install 命令会将 pack1.a 复制到本地包的路径 ($GOROOT/pkg) 下, 并会选择该路径下, 以不同操作系统命名的子目录, 之后在应用程序中导入 pack1 包时, 只需使用import ”pack1”.

如果上述操作不被允许, 则可使用 6/9g 和-I 选项进行构建:
在这里插入图片描述
-I 选项可将包名加入到编译器的包检索列表中, 而-L 选项可实现 6/8l 的链接:
在这里插入图片描述
在使用测试工具 go test 时, 还会遇到自定义包的构建, 参见第 13 章.

9.6 生成自定义包的文档 (godoc)

首先 godoc 工具可用于提取自定义包的注释信息, 这类注释必须使用//开始, 并在声明 (包声明, 类型声明, 函数声明等) 之前, 同时注释和声明之间不能包含空白行,godoc 可生成一系列 html 页面, 并会为每个 go 文件生成一个页面.
• 在系统路径的 doc_example 目录中, 提供了 sort 和 sortmain 文件, 参见 11.7 节, 同时在 sort 文件中(该文件无须编译) 给出了一些注释.
• 在命令行中, 使用godoc -http=:6060 -path=”.”, 进入 doc_example 目录, 其中. 表示当前目录, 而-path选项可实现路径变换, 如果存在多个路径, 可使用: 进行分隔.
• 启动网页浏览器, 输入地址http://localhost:6060.

在初始 godoc 页面中, 从左到右将出现一些超链接, 即 doc_example | Packages | Commands | Specification, 初始页面为 doc_example, 进入对应的链接, 将看到源码中包含所有对象, 点击这些对象, 可直接显示对应的代码 (这是一种查找代码的超链接方式), 这就是自定义包的对应文档和注释.

如果是一个开发团队, 那么源码树将保存在网络盘, 使用 godoc 可创建一个连续的文档, 以便提供给所有队员,如果给出 sync 或 sync_minutes=n 选项, godoc 可在 n 分钟之内, 实现文档的自动更新.

9.7 安装自定义包 (go install)

go install 可实现包的自动化安装, 通常需要通过互联网, 从远端的源码仓库中下载一个包, 并将其安装到本地机 (同时安装过程包含了验证安装, 编译和安装).

可命令行中, 使用 go install 工具实现包的安装, 当工具准备安装一个包时, 将会自动处理依赖关系, 包的依赖关系都放入到安装后的包目录中, 当包的文档和示例则不会放入到包目录.

在$GOROOT/goinstall.log 文件中, 可找到已安装包的列表, 同时 go install 工具还将使用 GOPATH 环境变量.

包删除

假定需要安装一个 tideland 包 (其中包含了一些有价值的程序), 它的介绍页面为http://code.google.com/p/tideland-cgl/. 由于需要在 Go 的系统目录中, 创建一些同名的包目录, 因此需要获取超级用户的身份, 或是使用 su 命令. 在超级用户的.bashrc 文件中, 需正确设置 Go 的环境变量, 之后可使用以下命令, 进行 tideland包的安装:
在这里插入图片描述
之后将在$GOROOT/pkg/linux_amd64/tideland-cgl.googlecode.com 目录下, 放入文件 hg.a, 同时会将 tideland 包的所有 go 文件, 放入 $GOROOT/src/tideland-cgl.googlecode.com/hg 目录, 同时 hg.a 文件将放入一个子目录 _obj.

之后在应用代码中, 可在 tideland 包的导入时, 为其配置一个自定义名称, 比如 cgl:
在这里插入图片描述
同时也期待能够使用页面路径的导入格式, 比如”code.google.com/p/tideland-cgl”.

Go 语言的版本更新

当完成 Go 语言的版本更新之后, 在本地已安装的包, 都将被删除, 调用 go install 可进行已安装包的重复安装可在$GOROOT/goinstall.log 文件中, 查看到相关细节, 如果需要更新, 重新编译和重新安装所有的 Go 包, 可使用以下语句:
在这里插入图片描述
由于 Go 语言的版本更新很频繁, 必须小心验证版本信息以及安装包,Go 1 版本之后可了解到足够的信息,go install 也可使用编译和链接工具, 实现自定义包的安装, 参见 9.8.2 节, 而这些工具的更多细节, 可查看页面http://golang.org/cmd/go/ 和http://golang.org/cmd/goinstall/.

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

为了了解自定义包的开发过程, 这里将给出一个简单包 uc, 其中将包含一个函数 UpperCase, 它可将一个字符串的所有字符, 都转换成大写字符, 当然 uc 包并无实际价值, 同时 uc 包还封装了 string 包的同名函数, 并且还引入了复杂包所需的一些技术.

9.8.1 目录结构

首先我们需要了解 uc 包的存储方式:
在这里插入图片描述
无论 Go 系统目录放在何处, 都可创建一个环境变量 GOPATH, 标记系统目录的位置, 也就是在.profile和 .bashrc文件中, 设定export GOPATH=/home/user/goprograms, 而包文件将放置在 src 子目录中, 在 uc.go 文件中实现了功能, 将包含在 uc 包中:

例 9.6 uc.go

在这里插入图片描述
在包文件中, 必须提供一个或多个测试文件, 比如 uc_test.go:

例 9.7 uc_test.go

在这里插入图片描述
在这里插入图片描述
使用命令 go install src/uc, 可实现本地包的构建和安装, 同时 uc.a 将复制到 pkg/linux_amd64 目录. 如果选择 make 进行构建和安装, 则需将 src/uc 目录, 写入包的 Makefile, 如下:
在这里插入图片描述
在命令行中, 如果直接进入 uc 目录, 可使用命令 gomake, 它创建 _obj 目录, 并将编译完成的 uc.a 文件, 复制到该目录下. 同时包文件还可使用 go test 进行测试, 该命令可创建 _test 目录 (也会将 uc.a 文件复制到其中), 如果相关的测试结果为 OK, 那么输出结果为 PASS, 在 13.8 节, 还给出 gotest 的另一个示例, 以深入讨论该工具的用法.

如果当前账号没有足够的权限, 来执行 go install, 则需要使用 su 命令, 切换到超级用户, 同时确保在超级用户的账号中, 已配置好 Go 语言的环境变量.

例 9.8 ucmain.go

在这里插入图片描述
可简单使用 go install 进行构建, 或是复制 uc.a 到 uc 目录中, 并修改 Makefile:
在这里插入图片描述
如果使用 gomake, 将 ucmain.go 文件编译成 ucmain 可执行文件, 使用./ucmain 命令, 运行该应用程序时, 出现 uc 包无法找到的问题.

9.8.2 包的本地安装

用户目录下的本地包

基于目录结构, 可使用以下命令, 本地安装包含源码的包.
在这里插入图片描述
在这里插入图片描述

基于$GOROOT 的安装

如果自定义包需要使用 Go 系统中包含的程序, 则必须基于环境变量$GOROOT 实现安装. 首先在.profile
或.bashrc 文件中, 设定GOPATH = $GOROOT, 之后输入命令 go install uc, 再执行以下操作:
• 将包的源码复制到$GOROOT/src/pkg/linux_amd64/uc 目录下.
• 将编译生成的包文件, 复制到$GOROOT/pkg/linux_amd64/uc 目录下.

然后就可在应用程序的代码中, 导入 uc 库.

9.8.3 与操作系统相关的代码

基于不同的操作系统, 需提供不同代码的情景相当稀少, 在大多数情况下, 编程语言和标准库都可处理绝大多数的移植问题. 如果需要编写与平台相关的代码, 比如提供汇编语言的支持, 即使在这种条件下, 也可应遵守以下约定:
在这里插入图片描述
prog1.go 定义了不同操作系统中, 可公用的代码接口, 同时将与操作系统相关的代码, 都放入 prog1_os.go 文件中, 为了 Go 工具的应用, 可为不同操作系统, 定义不同的 go 文件.

9.9 git 工具

9.9.1 github 安装

之前了解了本地包的处理, 那么如何将源码发布到编程社区? 这时我们需要一个云端的源码的版本控制系统,比如目前的主流系统 git.

在 Linux 和 OS X 系统中,git 属于默认安装, 但在 Windows 系统中, 则必须手动安装, 可参考页面 http://help.github.com/win-set-up-git/提供的相关信息.

在 9.8 节中, 为 uc 包创建了一个 git 源码仓库, 即进入 uc 包的目录, 使用 git init 命令, 就可创建一个 git 源码仓库, 创建完成后, 将出现信息:
在这里插入图片描述
每个 git 项目都需要一个 README 文件, 用于描述该 Go 包, 打开一个文本编辑器, 即可生成一个 README文件. 之后可将所有文件加入到 git 仓库中:
在这里插入图片描述
连接 github 主页https://github.com, 注意首先必须完成用户登录, 如果你没有登录, 也可去往页面https://
github.com/plans, 为开源项目创建一个免费账号, 输入账号的用户名和密码, 提供一个有效的邮件地址, 点击页面下部的 Create an Account(创建一个账号), 之后将看到一组 git 命令, 有些命令已在本地仓库中使用过了,在 git 使用中遇到的任何问题, 都可查找页面http://help.github.com/获取帮助.

为了在云端, 创建一个新仓库 uc, 可使用以下命令 (NNNN 为用户名):
在这里插入图片描述
使用 go check 可检查自定义包 uc 的 github 页面, 即https://github.com/NNNN/uc.

9.9.2 github 用法

如果需要从远端源码仓库中, 将 Go 包文件安装到本地机, 可在控制台启动一个安装任务:
在这里插入图片描述
上述语句可执行以下操作:
• 将包文件 uc.a 复制到$GOROOT/pkg/linux_amd64/github.com 目录下
• 将包的源码文件, 复制到$GOROOT/src/pkg/github.com/NNNN/uc 目录下

之后可在应用程序的 import 语句中, 使用”github.com/NNNN/uc” 替换”./uc/uc” 路径. 同时还可在 import
语句中设定一个包名, 如下:
在这里插入图片描述
或是在 Makefile 文件中修改以下内容:
在这里插入图片描述
而 Gomake(与 go install) 将工作在$GOROOT 目录下的本地 Go 版本.

其他版本控制系统和源码仓库

以下给出了主流的源码仓库, 在 () 中标注了版本控制系统:
• bitbucket (hg)
• github (git)
• googlecode (hg/git/svn)
• launchpad (bzr)

选择一种熟悉的版本控制系统, 有利于实现本地机的源码同步,Mercurial(hg) 是 Go 源码的中心仓库所采用的版本控制系统, 因此使用这类版本控制系统, 可保证开发者能在第一时间实现源码的同步, 同时 Git 系统也相当流行, 如果读者还未使用过版本控制系统, 可利用 Google 搜索引擎, 使用{name} tutorial(name 为版本控制系统的名称) 关键字, 能检索到一些质量很高的入门教程 (HOWTO 文档).

9.10 Go 语言的扩展包和扩展项目

经过之前的章节, 我们已掌握 Go 语言和标准库的基本用法, 但 Go 语言的生态系统 (ecosystem) 相当庞大,当读者准备创建自定义的 Go 项目时, 如果一些第三方包或是项目无法使用, 可首先进行搜索, 之后可使用 goinstall 工具进行安装.

进行检索的首个地方, 即 Go 官网 Package Dashboard 的 Projects 栏, 页面为http://godashboard.appspot.com/project, 这是一个人工收集的列表, 并给出了一些重要的分类, 比如 Build Tools(构建工具),Compression(数据压缩), Data Structures(数据结构),Databases and Storage(数据库和存储),Development Tools( 开发工具) 等,其中包含的项目已经超过 500 个, 每个项目都会给出项目名, 简明介绍和下载链接, 并可在以下的源码仓库中找到它们, 源码仓库之后将给出对应的版本控制系统:
• Google Code: http://code.google.com/p/goprotobuf/,(Mercurial(hg) or Subversion)
• Github: https://github.com/kr/pretty.go,(Git)
• BitBucket: https://bitbucket.org/binet/igo/,(Mercurial(hg))
• Launchpad: http://launchpad.net/mgo,(Bazaar)

源码也可能放置在共享页面中, 或是直接放置在作者的主页中.

经过管理员的协调后, 读者也可将自己的项目, 发布到源码仓库中, 之后通过http://godashboard.appspot.com/package 页面, 查看到自己的项目是否被 Go 官网收录.

在 Go 官网的 Packages 标签栏下, 还将给出 Most Installed Packages( 之前和本周的累加安装次数) 和 Recently Installed Packages(本周的安装次数), 它们分别表示开发者的安装次数. 如果该包的构建状态为 ok, 则表示该包已被安装到 Go 的最新版本中. 同时 Go Projects 和 Go Packages 不存在相关性, 如果包出现在一个分类中, 则不会出现在另一个分类中.

在 Package Dashboard 页面中, 还存在以下分类:
• http://go-lang.cat-v.org/dev-utils (开发方向)
• http://go-lang.cat-v.org/go-code (编程和应用)
• http://go-lang.cat-v.org/library-bindings (库的绑定)
• http://go-lang.cat-v.org/pure-go-libs (纯 Go 库)

同时 Go 语言已包含了大量的扩展库, 比如:
• MySQL(GoMySQL), PostgreSQL(go-pgsql), MongoDB(mgo, gomongo), CouchDB(couch-go), ODBC(godbcl),Redis(redis.go) 和 SQLite3(gosqlite) 的数据库驱动器
• SDL 绑定
• Google 的协议缓冲 (goprotobuf),
• XML-RPC(go-xmlrpc)
• Twitter(twitterstream),
• OAuth 库 (GOAuth)

9.11 扩展库的用法

在第 19-21 章将分别介绍 web 应用的构建和 Google App 引擎的用法, 这时还将深入讨论扩展库的用法.

当开始一个新项目, 或是为项目添加新功能时, 都可在应用中, 使用已存在的 Go 库, 以节省开发时间, 为了理解库 API(应用编程接口) 的用法, 也就是了解可调用的方法以及如何调用, 通常情况下, 库的源码无须改动,只是需要阅读 API 的文档.

比如编写一个使用 urlshortener(Google API) 的小程序, 功能如下, 首先连接http://goo.gl/ 页面, 并在页面中,输入一个 URL(http://www.destandaard.be), 这时可返回另一个页面http://goo.gl/O9SUO, 这使得嵌入操作更加容易, 也与 twitter 的一个服务很相似, 而 urlshortener 的相关文档, 可在http://code.google.com/apis/urlshortener/页面中查找, 在第 19 章中, 将开发一个自定义的 urlshortener.

Google 允许我们在自己的应用程序章, 调用其他开发者实现的 API(如果 API 需收费, 则存在限制), 因此可创建一个 Go client(客户端) 库, 以使类似的开发更简单.

Google 为了简化 Go 语言的开发, 为用户提供了 Google API, 这使得 Go 客户端程序能够基于 Google 库的JSON 描述而自定生成, 从 http://code.google.com/p/google-api-go-client/页面可获得更详细的信息.

Go client 库的下载和安装

这类操作可使用 go install 工具, 但首先需要确认 GOPATH 环境变量, 因为外部源码将下载到 $GOPATH/src目录下, 同时包将安装到 $GOPATH/pkg/”machine_arch”/目录下.之后通过命令行, 可实现 API 的安装, 如下:
在这里插入图片描述
go install 工具可实现包源码的下载, 编译和安装, 如果在 Ubuntu 系统下使用了 6g r609481 版本, 那么包的安装目录为pkg/linux_amd64.

使用 urlshortener 功能的 web 程序

在应用程序中, 可使用一个假名, 将包导入, 以便在应用程序中使用该包, 如下:
在这里插入图片描述
在第 15 章中, 我们将编写一个 web 应用, 它可实现长 URL 和短 URL 之间的转换, 同时将利用上述包, 编写三个处理函数, 一是 URL 基本 (根) 地址处理器, 可直接调用包函数, 二是短 URL 处理器, 可传入一个长URL, 并返回一个短 URL, 三是长 URL 处理器, 与短 URL 处理器功能相反.

为了调用 urlshortener API, 首先需要创建一个服务器实例 urlshortenerSvc, 如下:
在这里插入图片描述
同时会使用 http 包的默认客户端. 为了获得短 URL, 首先需要将长 URL 充填到 Url 结构, 并调用服务器
Url.Insert 方法的 Do 函数:
在这里插入图片描述
在 url 中, 将返回一个短 URL 地址. 为了获得长 URL 地址, 首先需要将短 URL 充填到 Url 结构, 并调用服务器 Url.Get 方法的 Do 函数:
在这里插入图片描述
在 url 中, 将返回一个长 URL 地址.

例 9.9 use_urlshortener.go

在这里插入图片描述
在这里插入图片描述
可对上述代码执行以下操作:
• 编译: 6g -I $GOPATH/pkg/linux_amd64 urlshortener.go
• 链接: 6l -L $GOPATH/pkg/linux_amd64 urlshortener.6
• 执行: ./6.out

如果能确保无其他应用程序在执行时, 则可运行http://localhost:8080, 通过http://localhost:8080 页面的浏览,也可测试 web 应用的执行结果. 为了简化代码, 这里没有对 err 进行检查, 在实际应用中, 必须对 err 进行检查.

变更为 Google App 引擎的应用

首先需修改之前的代码, 也就是将之前的应用程序变更为一个包, 如下:
• package main 改为 package urlshort
• func main() 改为 func init()

创建一个与包同名的目录, 即 urlshort, 将以下目录包含所有的源码, 复制到该目录中,
• google-api-go-client.googlecode.com/hg/urlshortener
• google-api-go-client.googlecode.com/hg/google-api

同时还需要一个配置文件 app.yaml, 如下:
在这里插入图片描述
之后可在控制台中, 运行之前构建的项目, 即dev_appserver.py urlshort, 这将启动一个 web 服务器, 同时可浏览器中, 输入地址http://localhost:8080, 启动一个 web 客户端.

在这里插入图片描述