跳转到主要内容

介绍


有时您的代码需要当前程序之外的其他功能。在这些情况下,您可以使用包来使您的程序更加复杂。包代表磁盘上单个目录中的所有文件。包可以定义您可以在其他 Go 文件或包中引用的函数、类型和接口。

本教程将引导您完成安装、导入和别名包。

标准库包


Go 附带的标准库是一组包。这些包包含许多编写现代软件的基本构建块。例如, fmt 包包含格式化和打印字符串的基本函数。 net/http 包包含允许开发人员创建 Web 服务、通过 http 协议发送和检索数据等功能。

要使用包中的功能,您需要使用 import 语句访问包。导入语句由 import 关键字和包名组成。

例如,在 Go 程序文件 random.go 中,您可以通过以下方式导入 math/rand 包来生成随机数:

random.go

import "math/rand"


当我们导入一个包时,我们将它作为一个单独的命名空间在我们当前的程序中可用。这意味着我们必须用点表示法来引用函数,就像在 package.function 中一样。

在实践中,math/rand 包中的函数可能类似于以下示例:

  • rand.Int() 调用函数返回一个随机整数。
  • rand.Intn() 调用该函数以返回从 0 到提供的指定数字的随机元素。

让我们创建一个 for 循环来展示如何在 random.go 程序中调用 math/rand 包的函数:

random.go

package main

import "math/rand"

func main() {
  for i := 0; i < 10; i++ {
    println(rand.Intn(25))
  }
}

该程序首先在第三行导入 math/rand 包,然后进入一个 for 循环,该循环将运行 10 次。在循环中,程序将打印一个 0 到 25 范围内的随机整数。整数 25 作为其参数传递给 rand.Intn()。

当我们使用 go run random.go 运行程序时,我们将收到 10 个随机整数作为输出。因为这些是随机的,所以每次运行程序时可能会得到不同的整数。输出将如下所示:

Output
6
12
22
9
6
18
0
15
6
0


整数永远不会低于 0 或高于 24。

当导入多个包时,可以使用 () 创建一个块。通过使用块,您可以避免在每一行重复导入关键字。这将使您的代码看起来更干净:

random.go

import (
  "fmt"
  "math/rand"
)


为了使用附加包,我们现在可以格式化输出并打印出在循环期间生成每个随机数的迭代:

random.go

package main

import (
  "fmt"
  "math/rand"
)

func main() {
  for i := 0; i < 10; i++ {
    fmt.Printf("%d) %d\n", i, rand.Intn(25))
  }
}

现在,当我们运行程序时,我们将收到如下所示的输出:

Output
0) 6
1) 12
2) 22
3) 9
4) 6
5) 18
6) 0
7) 15
8) 6
9) 0


在本节中,我们学习了如何导入包并使用它们来编写更复杂的程序。到目前为止,我们只使用了标准库中的包。接下来,让我们看看如何安装和使用其他开发人员编写的包。

安装包


虽然标准库附带了许多很棒且有用的包,但它们被有意设计为通用而不是特定的。这允许开发人员根据自己的特定需求在标准库之上构建自己的包。

Go 工具链附带 go get 命令。此命令允许您将第三方软件包安装到本地开发环境并在您的程序中使用它们。

当使用 go get 安装第三方包时,一个包被其规范路径引用是很常见的。该路径也可以是托管在 GitHub 等代码存储库中的公共项目的路径。因此,如果要导入 flect 包,您将使用完整的规范路径:

go get github.com/gobuffalo/flect


go get 工具将在 GitHub 上找到该包,并将其安装到您的 $GOPATH 中。

对于此示例,代码将安装在此目录中:

$GOPATH/src/github.com/gobuffalo/flect


原始作者经常更新软件包以解决错误或添加新功能。发生这种情况时,您可能希望使用该软件包的最新版本来利用新功能或解决的错误。要更新包,可以在 go get 命令中使用 -u 标志:

go get -u github.com/gobuffalo/flect


如果在本地找不到该软件包,此命令还将让 Go 安装该软件包。如果已经安装,Go 会尝试将包更新到最新版本。

go get 命令总是检索可用包的最新版本。但是,对于以前版本的软件包,可能会有比您现在使用的更新,并且对于在您的程序中进行更新很有用。要检索该特定版本的包,您需要使用包管理工具,例如 Go Modules。

从 Go 1.11 开始,Go Modules 用于管理要导入的包的版本。包管理的主题超出了本文的范围,但您可以在 Go Modules GitHub 页面上阅读更多相关信息。

别名导入的包


如果您的本地包已经与您正在使用的第三方包命名相同,您可能需要更改包名称。发生这种情况时,为您的导入设置别名是处理冲突的最佳方式。您可以通过在导入的包前面添加别名来修改 Go 中包的名称及其功能。

该语句的构造如下所示:

import another_name "package"


本例中,修改 random.go 程序文件中 fmt 包的名称。我们将 fmt 的包名更改为 f 以便缩写。我们修改后的程序将如下所示:

random.go

package main

import (
 f "fmt"
  "math/rand"
)

func main() {
  for i := 0; i < 10; i++ {
    f.Printf("%d) %d\n", i, rand.Intn(25))
  }
}

 

在程序中,我们现在将 Printf 函数称为 f.Printf 而不是 fmt.Printf。

虽然其他语言倾向于为包起别名以便在程序稍后使用,但 Go 不喜欢。例如,将 fmt 包别名为 f 与样式指南不一致。

在重命名导入以避免名称冲突时,您应该旨在重命名最本地或项目特定的导入。例如,如果您有一个名为 strings 的本地包,并且您还需要导入名为 strings 的系统包,那么您更倾向于重命名本地包而不是系统包。只要有可能,最好完全避免名称冲突。

在本节中,我们学习了如何为导入设置别名以避免与程序中的另一个导入冲突。重要的是要记住程序的可读性和清晰度很重要,因此您应该只使用别名来使代码更具可读性或需要避免命名冲突。

格式化导入


通过格式化导入,您可以将包排序为特定顺序,这将使您的代码更加一致。此外,当唯一改变的是导入的排序顺序时,这将防止发生随机提交。由于格式化导入将防止随机提交,这将防止不必要的代码搅动和混乱的代码审查。

大多数编辑器会自动为您格式化导入,或者让您将编辑器配置为使用 goimports。在编辑器中使用 goimports 被认为是标准做法,因为尝试手动维护导入的排序顺序可能很乏味并且容易出错。此外,如果进行了任何样式更改,goimports 将更新以反映这些样式更改。这可确保您和任何处理您的代码的人在您的导入块中具有一致的样式。

这是格式化之前的示例导入块的样子:

 

import (
  "fmt"
  "os"
  "github.com/digital/ocean/godo"
  "github.com/sammy/foo"
  "math/rand"
  "github.com/sammy/bar"
)


运行 goimport 工具(或使用大多数已安装它的编辑器,保存文件将为您运行它),您现在将具有以下格式:

import (
  "fmt"
  "math/rand"
  "os"

  "github.com/sammy/foo"
  "github.com/sammy/bar"

  "github.com/digital/ocean/godo"
)

 

请注意,它首先将所有标准库包组合在一起,然后将第三方包与空行组合在一起。这使得更容易阅读和理解正在使用的包。

在本节中,我们了解到使用 goimports 将保持我们所有的导入块格式正确,并防止在处理相同文件的开发人员之间发生不必要的代码搅动。

结论


当我们导入包时,我们可以调用 Go 中没有内置的函数。有些包是随 Go 一起安装的标准库的一部分,有些我们将通过 go get 安装。

文章链接