第九章第五至11节翻译内容

This commit is contained in:
Spawnris
2014-09-19 16:51:13 +08:00
parent e463d93a13
commit a4fff976c8
7 changed files with 450 additions and 0 deletions

BIN
eBook/09.10.md Normal file

Binary file not shown.

62
eBook/09.11.md Normal file
View File

@@ -0,0 +1,62 @@
#9.11 在Go程序中使用外部库
(本节我们将创建一个web应用和它的Google App Engine版本,在第19和21章分别说明当你阅读到这些章节时可以再回到这个例子。)
当开始一个新项目或增加新的功能到现有的项目你可以通过在应用程序中使用已经存在的库来节省开发时间。为了做到这一点你必须理解库的API应用编程接口那就是库中有哪些方法可以调用如何调用。你可能没有这个库的源代码但作者肯定有记载的API以及详细介绍了如何使用它。
作为一个例子我们将使用谷歌的API的urlshortener编写一个小程序你可以尝试一下在http://goo.gl/输入一个像"http://www.destandaard.be"这样的URL你会看到一个像"http://goo.gl/O9SUO"这样更短的URL返回也就是说在Twitter之类的服务中这是非常容易嵌入的。谷歌urlshortener服务的文档可以在"http://code.google. com/apis/urlshortener/"找到。 (第19章我们将开发自己版本的urlshortener)。
谷歌将这项技术提供给其他开发者作为API我们可以在我们自己的应用程序中调用释放到指定的限制。他们也生成了一个Go语言客户端库使其变得更容易。
备注谷歌让通过使用Google API Go客户端服务的开发者生活变得更简单Go客户端程序自动生成于Google库的JSON描述。更多详情在http://code.google.com/p/google-api-go-client/。
下载并安装Go客户端库:
将通过go install实现。但是首先要验证环境变量中是否含有GOPATH变量因为外部源码将被下载到$GOPATH/src目录下并被安装到$GOPATH/PKG/"machine_arch"/目录下。
我们将通过在终端调用以下命令来安装API:
go install google-api-go-client.google.com/hg/urlshortener/v1
go install将下载源码编译并安装包
(在Linux Ubuntu下使用6g r60 9841安装是可以的,被安装文件被放在pkg/linux_amd64下)
使用urlshortener服务的web程序:
现在我们可以通过导入并赋予别名来使用已安装的包import urlshortener "google-api-go-client.googlecode.com/hg/urlshortener/v1"
现在我们写一个web应用(参见第十五章4-8节)通过表单实现短地址和长地址的相互转换。我们将使用template包并写三个处理函数root函数通过执行表单模板来展示表单。short函数将长地址转换为短地址long函数逆向转换。
要调用urlshortener接口必须先通过http包中的默认客户端创建一个服务实例urlshortenerSvc
urlshortenerSvc, _ := urlshortener.New(http.DefaultClient)
我们通过调用服务中的Url.Insert中的Do方法传入包含长地址的Url数据结构从而获取短地址
url, _ := urlshortenerSvc.Url.Insert(&urlshortener.Url{LongUrl: longUrl}).Do()
返回url的Id便是我们需要的短地址。
我们通过调用服务中的Url.Get中的Do方法传入包含短地址的Url数据结构从而获取长地址
url, error := urlshortenerSvc.Url.Get(shwortUrl).Do()
返回的长地址便是转换前的原始地址。
实例 9.9 [urlshortener.go](examples/chapter_9/urlshortener.go)
package main
import (
“fmt”
“net/http”
“text/template”
rlshortener “google-api-go-client.googlecode.com/hg/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(`

139
eBook/09.5.md Executable file
View File

@@ -0,0 +1,139 @@
#B 自定义和外部包的使用,编译,测试,文档和安装
#9.5 自定义包和可见性
包是Go语言中代码组成和代码编译的主要方式。很多关于它们的基本信息已经在4.2章节中给出,最引人注目的便是可见性。现在我们来看看具体如何来使用自己写的包。在下一节,我们将回顾一些标准库中的包,自定义的包和标准库以外的包。
当写自己包的时候要使用短小的不含有_(下划线)的小写单词来为文件命名。这里有个简单例子来说明包是如何相互调用以及可见性是如何实现的。
当前目录下(examples/chapter9)有一个名为package_test.go的程序, 它使用了自定义包pack1中pack1.go的代码。这段程序(联通编译链接生成的pack1.a)存放在当前目录下一个名为pack1的文件夹下。所以链接器将包的对象和主程序对象链接在一起。
示例 9.4 [pack1.go](exmaples/chapter_9/pack1.go)
package pack1
var Pack1Int int = 42
var PackFloat = 3.14
func ReturnStr() string {
return "Hello main!"
}
它包含了一个整型变量PackInt和一个返回字符串的函数ReturnStr。这段程序在运行时不做任何的事情因为它不包含有一个main函数。
在主程序pack_test.go中这个包通过声明的方式被导入
import “./pack1/pack1”
import的一般格式如下:
import “包的路径或url地址“ 像 import "github.com/org1/pack1”
路径是指当前目录的相对路径。
示例 9.5 [package_test.go](exmaples/chapter_9/package_test.go)
package main
import (
"fmt"
"./pack1/pack1"
)
func main() {
var test1 string
test1 = pack1.ReturnStr()
fmt.Printf("ReturnStr from package1: %s\n", test1)
fmt.Printf(“Integer from package1: %d\n”, pack1.Pack1Int)
// fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)
输出结果:
ReturnStr from package1: Hello main!
Integer from package1: 42
如果包pack1和我们的程序在统同一路径下我们可以通过"import ./pack1"这样的方式来引入,但这不被视为一个好的方法。
fmt.Printf(“Float from package1: %f\n”, pack1.pack1Float)这行代码试图访问一个未引用的变量或者函数,甚至没有编译。将会返回一个错误:
cannot refer to unexported name pack1.pack1Float
主程序利用的包必须在主程序编写之前被编译。主程序中每个pack1项目都要通过包名来使用使用pack1.Item。具体使用方法请参见示例4.6和4.7。
因此,按照惯例子目录和包之间有着密切的联系:为了区分不同包存放在不同的目录,每个包(所有属于这个包中的go文件)都存放在和包名相同的子目录下。
Import with . : import . “./pack1”
当使用.来做为包的别名时你可以不通过包名来使用其中的项目。例如test := ReturnStr()。
在当前的命名空间导入pack1包一般是为了具有更好的测试效果。
Import with _ : import _ “./pack1/pack1”
pack1包只导入其副作用只执行了它的init函数并初始化了其中的全局变量
导入外部安装包:
如果你要在你的应用中使用一个或多个外部包首先你必须使用go install(参见9.7章节)在你的本地机器上安装它们。
假设你想使用http://codesite.ext/author/goExample/goex这种托管在googlecode, github,launchpad等代码网站上的包。
你可以通过如下命令安装
go install codesite.ext/author/goExample/goex
将一个名为codesite.ext/author/goExample/goex的map安装在$GOROOT/src/目录下。
通过以下方式,一次性安装,并导入到你的代码中:
import goex “codesite.ext/author/goExample/goex”
因此你项目的路径将成为导入包的网络地址
在http://golang.org/cmd/goinstall/的go install文档中列出了一些广泛被使用的托管在网络代码仓库的包的导入路径
包的初始化:
程序的执行开始于导入包初始化main包然后调用main函数。
一个没有导入的包将通过分配初始值给所有的包级变量和调用源码中定义的包级init函数来初始化。一个包可能有多个init函数甚至在一个源码文件中。它们的执行是无序的。这是最好的例子来测定包的值是否只依赖于相同包下的其他值或者函数。
init函数是不能被调用的。
导入的包在包自身初始化前被初始化,而一个包在程序执行中只能初始化一次。
编译并安装一个包(参见9.7章节):
在Linux/OSX下可以用类似4.3章节的Makefile脚本做到这一点
include $(GOROOT)/src/Make.inc
TARG=pack1
GOFILES=\
pack1.go\
pack1b.go\
include $(GOROOT)/src/Make.pkg
确保的它可执行性通过 chmod 777 ./Makefile。
内置声明了自动检测机器体系结构和使用正确的编译器和链接器的功能。
然后终端执行make或gomake:都会生成一个包含静态库pack1.a的_obj目录。
go install(参见9.7章节从Go1的首选方式)同样复制pack1.a到本地的$GOROOT/pkg的目录中一个以操作系统为名的子目录下。像 import "pack1"代替imort "path to pack1",这样只通过名字就可以将包在程序中导入。
如果不可取或不被允许通过6/8g使用-I选项来编译
6g—I map_pack1 package_test.go # where map_pack1 is the map which contains pack1.a
(I选项让编译器查找选项后的目录下是否包含这个包)
使用6/8l的-L选项链接
6l—L map_pack1 package_test.6
当第13章我们遇到使用测试工具进行测试的时候我们将重新回到自己的包的制作和编译这个话题。
练习:
问题9.1:

34
eBook/09.6.md Normal file
View File

@@ -0,0 +1,34 @@
# 9.6 为你的自定义包使用godoc
godoc工具(3.6章节)在显示自定义包中的注释也有很好的效果:注释必须以//开始并无空行放在声明(包,类型,函数)前。godoc会为每个文件生成一系列的网页。
例如:
-在do_examples目录下我们有11.7章节中的用来排序的go文件文件中有一些注释文件需要未编译
-命令行下进入目录下并输入命令:
godoc -http =:6060 -paht="."
(.是指当前目录,-path参数可以是/path/to/my/package1这样的形式指出package1在你源码中的位置或接受用冒号形式分隔的路径无根目录的路径为相对于当前目录的相对路径)
-在浏览器打开地址 http://localhost:6060
然后你会看到本地的godoc页面(参见3.6章节)从左到右一次显示出目录中的包
doc_example:
doc_example | Packages | Commands | Specification
下面是链接到源码和所有对象时有序概述(所以是很好的浏览和查找源代码的方式),连同文件/评论。
sort包
func Float64sAreSorted
type IntArray
func IntsAreSortedfunc IsSortedfunc Sort
func (IntArray) Len
func SortFloat64s

37
eBook/09.7.md Normal file
View File

@@ -0,0 +1,37 @@
# 9.7使用go install安装自定义包
go install是Go中自动包安装工具如需要将包安装到本地它会从远端仓库下载包检出编译安装一气呵成。
在包安装前的先决条件是要自动处理包自身依赖关系的安装。被依赖的包也会安装到子目录下,但是没有文档和示例:可以到网上浏览。
被安装包的列表可以在$GORROT/goinstall.log找到。
go install使用了GOPATH变量(参见2.2章节)。
远端包(参见9.5章节)
假设我们要安装一个有趣的包tideland(它包含了许多帮助示例参见http://code.google.com/p/tideland-cgl)。
因为我们需要创建目录在Go安装目录下所以我们需要使用root或者su的身份执行命令。
确保Go环境变量已经设置在root用户下的./bashrc文件中。
使用命令安装go install tideland-cgl.googlecode.com/hg
可执行文件hg.a将被放到$GOROOT/pkg/linux_amd64/tideland-cgl.googlecode.com目录下源码文件被放置在$GOROOT/src/tideland-cgl.googlecode.com/hg目录下同样有个hg.a放置在_obj的子目录下。
现在就可以在go代码中使用这个包中的功能了例如使用报名cgl导入
import cgl "tideland-cgl.googlecode.com/hg"
从Go1起go install安装Google Code的导入路径形式是"code.google.com/p/tideland-cgl"
升级到新的版本:
更新到新版本的Go之后本地安装包的二进制文件将全被删除。当调用install-a工具将通过读取$GOROOT/goinstall.log重新安装以前的安装包。如果你想更新重编译重安装所有的go安装包可以使用go install -a -u -clean 或者 go install -a -u -nuke
go的版本发布的很频繁所以需要注意发布版本和包的兼容性。go1之后都是自己编译自己了。
go install同样可以使用go install编译链接并安装本地自己的包参见9.8.2章节。
更多信息可以在http://golang.org/cmd/go和http://golang.org/cmd/goinstall找到。

124
eBook/09.8.md Executable file
View File

@@ -0,0 +1,124 @@
#9.8 自定义包:目录结构,go install和go test
为了示范我们创建了一个名为uc的简单包,它含有一个UpperCase函数将字符串的所有字母转换为大写。当然这并不值得创建一个自己包同样的功能已被包含在"strings"包里,但是同样的技术也可以应用在更复杂的包中。
##9.8.1 自定义包的目录结构
下面的结构给了你一个好的示范(uc代表通用包名, 名字为粗体的代表目录,斜体代表可执行文件):
/home/user/goprograms
ucmain.go (uc包主程序)
Makefile (ucmain的2-makefile)
ucmain
src/uc (包含uc包的go源码)
uc.go
uc_test.go
Makefile (包的1-makefile)
uc.a
_obj
uc.a
_test
uc.a
bin (包含最终的执行文件)
ucmain
pkg/linux_amd64
uc.a (包的目标文件)
将你的项目放在goprograms目录下(你可以创建一个环境变量GOPATH,参考2.2/3章节:在.profile和.bashrc文件中添加export GOPATH=/home/user/goprograms)而你的项目将作为src的子目录。uc包 中的功能在uc.go中实现。
示例 9.6 [uc.go](exmaples/chapter_9/uc.go)
package uc
import "strings"
func UpperCase(str string) string {
return strings.ToUpper(str)
}
包通常附带一个或多个测试文件在这我们创建了一个uc_test.go文件如9.8章节所述
示例 9.7 [test.go](examples/chapter_9/uc.go)
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 src/uc, 这会将uc.a复制到pkg/linux_amd64下面
另外使用make,通过以下内容创建一个包的Makefile(1)在src/uc目录下:
include $GOROOT/src/Make.inc
TARG=uc
GOFILES=\
uc.go\
include $(GOROOT)/scr/Make.pkg
在该目录下的命令行调用: gomake
这将创建一个_obj目录并将包编译生成的存档uc.a放在该目录下
这个包可以通过go test测试
创建一个ud.a的测试文件在目录下输出为PASS时测试通过
在13.8章节我们将给出另外一个测试例子并进行深入研究
备注有可能你当前的用户不具有足够的资格使用go install(没有权限)。这种情况下选择root用户su。确保Go环境变量和Go源码路径也设置给su同样也适用你的普通用户(详见2.3章节)
接下来我们创建主程序ucmain.go:
示例 9.8 [ucmain.go](/examples/chapter_9/ucmain.go)
package main
import (
"fmt"
"./uc/uc"
)
func main() {
str1 := "USING package uc"
fmt.Println(uc.UpperCase(str1))
}
然后在这个目录下输入go install
另外复制uc.a到uc目录并创建一个Makefile(2)并写入文本:
包含在$GOROOT/src/Make.inc
TARG=ucmain
GOFILES=\
ucmain.go\
include $GOROOT/src/Make.cmd
执行gomake编译ucmain.go到ucmain目录
运行./ucmain显示: USING package uc!
## 9.8.2 本地安装包
本地包在用户目录下:
使用给出的目录结构,以下命令用来从源码安装本地包:
go install /home/user/goprograms/src/uc # 编译安装uc
cd /home/user/goprograms/uc
go install ./uc # 编译安装uc和之前的指令一样
cd ..

54
eBook/09.9.md Normal file
View File

@@ -0,0 +1,54 @@
#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仓库在里面: git init .
信息提示: Initialized empty git repository in .../uc
每一个git项目都需要一个对包进行描述的README文件,所以打开你的文本编辑器(gedit,notepad,LiteIde)添加一些说明进去。
然后添加所有文件到仓库git add README uc.go uc_test.go Makefile
标记为第一个版本: git commit -m "initial rivision"
现在必须去登录github网站: https://github.com
也许你还不能登录你可以去https://github.com/plans注册一个开源项目的免费帐号。输入正确的帐号密码和有效的邮箱地址并进一步创建用户。然后你将获得一个git命令的列表。本地仓库的操作的命令已经完成。一个优秀的系统http://help.github.com/在你遇到任何问题的时候将引导你。
在云端创建一个新的uc仓库;发布的指令为(NNNN替代用户名):
git remote add orign git@github.com:NNNN/uc.git
git push -u origin master
操作完成后检查github上的包页面: http://github.com/NNNN/uc
##9.9.2 从github安装
如果有人想你的远端项目到本地机器,打开终端并执行: go install github.com/NNNN/uc
NNNN是你在github上的用户名
复制
->uc.a包到目录$GOROOT/PKG/LINUX_AMD64/github.com
->源码到$GOROOT/src/pkg/github.com/NNNN/uc
这样现在这台机器上的其他Go应用程序也可以通过导入路径"github.com/NNNN/uc"代替"./uc/uc"来使用。
也可以将其缩写为: import uc "github.com/NNNN/uc"
然修改Makefile: 将TARG=uc替换为TARG-github.com/NNNN/uc
Gomake(和go install)将通过$GOROOT下的本地版本进行工作。
网站和版本控制系统:其他的选择
主要网站有(括号中为网站所使用的版本控制系统)
* bitbucket(hg)
* github(git)
* googlecode(hg/git/svn)
* launchpad(bzr)