编写Go 代码是一种有趣而愉快的经历,编译时错误而不是痛苦实际上会引导您编写健壮、高质量的代码。然而,时不时地,你会遇到一些环境问题,这些问题开始阻碍你,并破坏你的生活。虽然您通常可以在进行一些搜索和稍作调整后解决这些问题,但正确设置开发环境对于减少问题有很大帮助,使您能够专注于构建有用的应用程序。
在本章中,我们将在一台新机器上安装“从头开始”,并讨论我们的一些环境选项以及它们在未来可能产生的影响。我们还将考虑协作可能如何影响我们的一些决策,以及影响我们的软件包可能有哪些开放源代码。
具体而言,我们将:
- 获取 Go 源代码并在您的开发机器上以本机方式构建它
- 了解
GOPATH
环境变量的用途,并讨论合理的使用方法 - 了解 Go 工具以及如何使用它们来保持代码的高质量
- 了解如何使用工具自动管理我们的导入
- 想想我们的
.go
文件的“保存”操作,以及我们如何将 Go 工具集成到日常开发中
Go 是一个开源项目,最初是用 C 语言编写的,这意味着我们可以很容易地从代码中编译自己的版本;由于各种原因,这仍然是安装 Go 的最佳选择。如果我们以后需要在标准库 Go 代码或工具的 C 代码中查找某些内容,它允许我们在源代码中导航。它还允许我们轻松地更新到 Go 的新版本,或者在发布候选版本时对其进行实验,只需从代码库中提取不同的标记或分支,然后再次构建。当然,如果需要的话,我们也可以轻松地回溯到更早的版本,甚至修复 bug 并生成拉请求发送给 GO 核心团队,让他们考虑对项目的贡献。
在线可以找到从其来源在各种平台上安装 Go 的不断更新的资源 http://golang.org/doc/install/source 或通过搜索Install Golang from source
。本章将介绍同样的内容,但如果你遇到问题,互联网将成为你帮助解决问题的最好朋友。
因为Go 工具链是用 C 编写的,所以我们在构建 Go 安装时实际上是在编译 C 代码。这似乎有点违反直觉;一种编程语言是用另一种编程语言编写的,但当然,当 Go 核心团队开始编写 Go 时,Go 并不存在,但 C 确实存在。更准确地说,用于构建和链接 Go 程序的工具是用 C 编写的。无论哪种方式,现在我们都需要能够编译 C 源代码。
2014 年,在科罗拉多州丹佛举行的首次 Gophercon 大会上,Rob Pike 及其团队表示,他们的目标之一是用 Go 编写的程序取代 C 工具链,从而使整个堆栈成为 Go。在编写本文时,这还没有发生,所以我们需要 C 工具。
要确定是否需要安装 C 工具,请打开终端并尝试使用gcc
命令:
gcc -v
如果您收到command not found
错误或类似错误,您可能必须安装 C 工具。但是,如果您看到gcc
的输出为您提供了版本信息(这就是-v
标志的作用),您可能会跳过这一部分。
安装C 工具因平台而异,可能会随着时间的推移而改变,因此本节仅作为一个粗略的指南,帮助您获得所需的工具。
运行 OS X 的 Mac 上的工具随 Xcode 一起提供,Xcode 在 App Store 中免费提供。安装 Xcode 后,打开首选项并导航到下载部分。从那里,您可以找到命令行工具,其中包括构建 Go 所需的 C 工具。
在 Ubuntu 和 Debian 系统上,您可以使用apt-get
安装工具:
sudo apt-get install gcc libc6-dev
对于 RedHat 和 Centos 6 系统,您可以使用yum
安装工具:
sudo yum install gcc glibc-devel
对于 Windows,MinGW 项目提供了一个 Windows 安装程序,可以为您安装这些工具。导航到http://www.mingw.org/ 然后按照那里的说明开始。
一旦您成功安装了这些工具并确保您的PATH
环境变量中包含了适当的二进制文件,您应该能够在运行gcc -v
时看到一些合理的输出:
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.2.0
Thread model: posix
前面的代码片段是苹果 Mac 电脑上的输出,最重要的是没有command not found
错误。
Go 源代码托管在 Mercurial 存储库中的 Google 代码中,因此我们将使用hg
命令克隆它以准备构建。
如果您没有hg
命令,可以从的下载页面获取 Mercurialhttp://mercurial.selenic.com/downloads 。
在终端中,要安装 Go,请导航到合适的位置,如 Unix 系统上的/opt
或 Windows 上的C:\
。
通过键入以下命令获取Go 的最新版本:
hg clone -u release https://code.google.com/p/go
过一会儿,最新的 Go 源代码将下载到一个新的go
文件夹中。
导航到刚刚创建的go/src
文件夹并运行all
脚本,该脚本将根据源代码构建 Go 的实例。在 Unix 系统上这是all.bash
,在 Windows 上这是all.bat
。
完成所有构建步骤后,您应该注意到所有测试都已成功通过。
Go 现在已经安装了,但为了使用这些工具,我们必须确保其配置正确。为了使调用工具更容易,我们需要将我们的go/bin
路径添加到PATH
环境变量中。
在 Unix 系统上,您应该将导出PATH=$PATH:/opt/go/bin
(确保它是下载源代码时选择的路径)添加到您的.bashrc
文件中。
在 Windows 上,打开系统属性(尝试右键点击我的电脑),在高级下,点击环境变量按钮,并使用 UI 确保PATH
变量包含到go/bin
文件夹的路径。
在终端中(您可能需要重新启动它才能使更改生效),您可以通过打印PATH
变量的值来确保这一点:
echo $PATH
确保打印的值包含到您的go/bin
文件夹的正确路径,例如,在我的机器上打印为:
/usr/local/bin:/usr/bin:/bin:/opt/go/bin
路径之间的冒号(Windows 上的分号)表示PATH
变量实际上是文件夹列表,而不仅仅是一个文件夹。这表示在终端中输入命令时,将搜索包含的每个文件夹。
现在我们可以确保我们刚刚进行的 Go 构建成功运行:
go version
像这样执行go
命令(可以在您的go/bin
位置找到)将为我们打印当前版本。例如,对于 Go 1.3,您应该看到类似的内容:
go version go1.3 darwin/amd64
GOPATH
是文件夹中的另一个环境变量(如前一节中的PATH
,用于指定 Go 源代码和已编译二进制软件包的位置)。在 Go 程序中使用import
命令将导致编译器在GOPATH
位置查找您所引用的包。使用go get
等命令时,项目下载到GOPATH
文件夹中。
虽然GOPATH
位置可以包含以冒号分隔的文件夹列表,例如PATH
,而且您甚至可以根据您所从事的项目为GOPATH
设置不同的值,但强烈建议您对所有内容使用单个GOPATH
位置,这就是我们假设你们将为本书中的项目所做的。
创建一个名为go
的新文件夹,这次在您的Users
文件夹中的某个地方,可能在Work
子文件夹中。这将是我们的GOPATH
目标,也是所有第三方代码和二进制文件的最终归宿,也是我们编写 Go 程序和包的地方。使用上一节中设置PATH
环境变量时使用的相同技术,将GOPATH
变量设置为新的go
文件夹。让我们打开一个终端,使用其中一个新安装的命令获取第三方软件包供我们使用:
go get github.com/stretchr/powerwalk
从Stretchr
获取powerwalk
库实际上会导致创建以下文件夹结构;$GOPATH/src/github.com/stretchr/powerwalk
。您可以看到,路径段在 Go 如何组织事物方面非常重要,这有助于名称空间项目并保持它们的唯一性。例如,如果您创建了自己的名为powerwalk
的包,则不会将其保存在Stretchr
的 GitHub 存储库中,因此路径会有所不同。
当我们在这本书中创建项目时,你应该考虑一个明智的答案。例如,我使用了github.com/matryer/goblueprints
,如果您使用go get
,您将在GOPATH
文件夹中获得本书所有源代码的完整副本!
Go 核心团队早期做出的一个决定是,所有的 Go 代码对于讲 Go 的每个人来说都应该是熟悉和明显的,而不是每个需要额外学习的代码库,以便新程序员理解或使用它。当你考虑开源项目时,这是一个特别明智的方法,其中有些项目有数百个贡献者不断出现。
有一系列工具可以帮助我们实现 Go 核心团队设定的高标准,我们将在本节中看到一些工具的使用。
在您的GOPATH
位置,创建一个名为tooling
的新文件夹,并创建一个包含以下代码的新main.go
文件:
package main
import (
"fmt"
)
func main() {
return
var name string
name = "Mat"
fmt.Println("Hello ", name)
}
紧凑的空间和缺乏缩进是有意为之的,因为我们将看到一个非常酷的工具,它随 Go 一起提供。
在终端中,导航到新文件夹并运行:
go fmt
在科罗拉多州丹佛市举行的 2014 年 Gophercon 大会上,大多数人了解到,这个小三位一体的发音并不是“格式”或“f,m,t”,而是实际发音为一个单词。现在试着对自己说:“fhumt”;如果计算机程序员彼此不说一种陌生的语言,他们似乎还不够怪异!
你会注意到这个小工具实际上调整了我们的代码文件,以确保我们程序的布局(或格式)符合 Go 标准。新版本更容易阅读:
package main
import (
"fmt"
)
func main() {
return
var name string
name = "Mat"
fmt.Println("Hello ", name)
}
go fmt
命令关注缩进、代码块、不必要的空白、不必要的额外换行等等。以这种方式格式化代码是一种很好的做法,可以确保您的 Go 代码与所有其他 Go 代码一样。
下一步,我们将审查我们的程序,以确保我们没有犯任何错误或决策,可能会混淆我们的用户;我们可以使用另一个免费提供的强大工具自动完成此任务:
go vet
我们的小程序的输出指出了一个显而易见的错误:
main.go:10: unreachable code
exit status 1
我们在函数的顶部调用return
,然后尝试做其他事情。go vet
工具注意到了这一点,并指出我们的文件中有无法访问的代码。
如果您在运行任何 Go 工具时出错,通常意味着您必须先获取命令,然后才能使用它。但是,对于 vet 工具,您只需打开终端并运行:
go get code.google.com/p/go.tools/cmd/vet
go vet
会发现的不仅仅是像这样愚蠢的错误,它还会寻找程序中更微妙的方面,指导您编写最好的 Go 代码。有关 vet 工具将报告的内容的最新列表,请查看上的文档 https://godoc.org/code.google.com/p/go.tools/cmd/vet 。
我们将使用的最后一个工具称为goimports
,由 Brad Fitzpatrick 编写,用于自动修复(添加或删除)import
Go 文件语句。在 Go 中,导入一个包而不使用它是一个错误,显然,尝试使用一个包而不导入它也不会起作用。goimports
工具将根据代码文件的内容自动重写我们的import
语句。首先,让我们使用熟悉的命令安装goimports
:
go get code.google.com/p/go.tools/cmd/goimports
更新您的程序以导入一些我们不打算使用的包,并删除fmt
包:
import (
"net/http"
"sync"
)
当我们试图通过调用go run main.go
来运行程序时,我们会看到出现一些错误:
./main.go:4: imported and not used: "net/http"
./main.go:5: imported and not used: "sync"
./main.go:13: undefined: fmt
这些错误告诉我们,我们已经导入了我们没有使用的包,并且丢失了fmt
包,为了继续,我们需要进行更正。这就是goimports
的用武之地:
goimports -w *.go
我们正在使用-w
写入标志调用goimports
命令,这将节省我们对所有以.go
结尾的文件进行更正的任务。
现在查看您的main.go
文件,注意net/http
和sync
包已被移除,而fmt
包已放回。
您可能会争辩说,切换到终端来运行这些命令比手动执行要花更多的时间,而且在大多数情况下您可能是对的,这就是强烈建议您将 Go 工具与文本编辑器集成的原因。
由于Go 核心团队为我们提供了fmt
、vet
、test
和goimports
等伟大的工具,我们将研究一种被证明非常有用的开发实践。无论何时保存.go
文件,我们都希望自动执行以下任务:
- 使用
goimports
和fmt
修复我们的导入并格式化代码。 - 检查代码是否有任何错误,并立即告诉我们。
- 尝试生成当前包并输出任何生成错误。
- 如果构建成功,则运行包的测试并输出所有失败。
因为 Go 代码编译速度非常快(Rob Pike 曾经说过它的构建速度不快,但它并不像其他任何东西那样慢),所以每次保存文件时,我们都可以轻松地构建整个包。对于运行测试也是如此,如果我们是以 TDD 风格开发的,那么它可以帮助我们,而且体验非常好。每次我们对代码进行更改时,我们都可以立即看到我们是否破坏了某些东西或对项目的其他部分产生了意外的影响。我们再也不会看到包导入错误了,因为我们的import
语句已经为我们修复,我们的代码将在我们眼前正确格式化。
一些编辑器可能不支持针对特定事件运行代码,例如保存文件,这给您留下了两个选项;您可以切换到更好的编辑器,也可以编写自己的脚本文件,以响应文件系统的更改。后一种解决方案超出了本书的范围,相反,我们将关注如何在流行的文本编辑器中实现此功能。
Sublime Text 3是编写在 OS X、Linux 和 Windows 上运行的 Go 代码的优秀编辑器,具有极其强大的扩展模型,易于定制和扩展。您可以从下载升华文本 http://www.sublimetext.com/ 和免费试用,然后再决定是否购买。
感谢处置(见https://github.com/DisposaBoy ),那里已经有了一个很棒的 Go 扩展包,它实际上给了我们很多 Go 程序员实际上错过的功能和能力。我们将安装此GoSublime
软件包,然后在此基础上添加所需的保存功能。
在可以安装GoSublime
之前,我们需要将包控件安装到 Sublime 文本中。前往https://sublime.wbond.net/ 点击安装链接,获取如何安装 Package Control 的说明。在撰写本文时,只需复制一个虽然很长的行命令,并将其粘贴到 Sublime 控制台中,通过从菜单导航到视图****显示控制台即可打开该控制台。
完成后,按shift+命令+P并键入Package Control: Install Package
,选择选项后按返回。在短时间延迟后(Package Control 正在更新其列表),将出现一个框,允许您只需输入 GoPublime,选择它,然后按返回即可搜索并安装 GoPublime。一切顺利,GoPublime 将被安装,编写 Go 代码变得简单了一个数量级。
现在您已经安装了 GoSublime,您可以通过按命令+打开一个包含软件包详细信息的简短帮助文件。、命令+2(同时为命令键和句点,之后为命令键和编号2。
Tyler Bunnell 是 Go 开源社区中另一个流行的名字(参见https://github.com/tylerb )我们将使用他的定制来实现我们的保存功能。
按命令+。、命令+5打开 GoSublime 设置,向对象添加以下条目:
"on_save": [
{
"cmd": "gs9o_open",
"args": {
"run": ["sh", "go build . errors && go test -i && go test && go vet && golint"],
"focus_view": false
}
}
]
请注意,设置文件实际上是一个 JSON 对象,因此请确保在不损坏文件的情况下添加on_save
属性。例如,如果在前后都有属性,请确保有适当的逗号。
前面的设置将告诉 Sublime Text 在保存文件时构建代码以查找错误、安装测试依赖项、运行测试并检查代码。保存设置文件(暂时不要关闭它),让我们看看它的作用。
导航到从菜单中选择文件打开…并选择要打开的文件夹,现在让我们打开我们的tooling
文件夹。Sublime Text 的简单用户界面清楚地表明,目前我们的项目中只有一个文件,main.go
。单击该文件,添加一些额外的换行符,并添加和删除一些缩进。然后从菜单中导航到文件保存,或按命令+S。请注意,代码立即被清理,如果您没有从main.go
中删除奇怪放置的return
语句,您将注意到控制台已经出现,并且由于go vet
而报告了问题:
main.go:8: unreachable code
按住命令+shift并双击控制台中无法访问的代码行,将打开文件并将光标跳转到问题的右侧行。当您继续编写 Go 代码时,您可以看到此功能将有多大帮助。
如果您向文件中添加了不需要的导入,您会注意到,在使用on_save
时,您会被告知该问题,但它不会自动修复。那是因为我们还有另一个调整。在将on_save
属性添加到的相同设置文件中,添加以下属性:
"fmt_cmd": ["goimports"]
这告诉 GoSublime 使用goimports
命令而不是go fmt
。再次保存此文件并返回到main.go
。再次向导入中添加net/http
,删除fmt
导入,保存文件。请注意,未使用的包已被移除,fmt
再次被放回。
在本附录中,我们根据源代码安装了我们自己的 Go 版本,这意味着我们可以轻松地使用hg
命令使安装保持最新,或者在发布测试版功能之前测试它们。拥有完整的围棋语言代码,让我们在那些孤独的火炉之夜浏览,这也很好。
您了解了GOPATH
环境变量,并发现了为所有项目保留一个值的常见做法。这种方法大大简化了 Go 项目的工作,否则您可能会继续遇到棘手的失败。
我们发现了 Go 工具集如何真正帮助我们生成高质量、符合社区标准的代码,任何其他程序员都可以在不需要额外学习的情况下学习和处理这些代码。更重要的是,我们了解了自动化这些工具的使用意味着我们可以真正开始编写应用程序和解决问题,而这正是开发人员真正想要做的。