Go包基础与使用指南

Go 是一门鼓励良好软件工程实践的语言。高质量软件的一个重要部分是代码复用,遵循 DRY 原则------不要重复自己。Go 包(package)正是实现代码可复用性的一个方法。

什么是包?

简单来说,Go 包就是项目中的一个目录,它包含一个或多个 Go 源文件,甚至还可以包含其他嵌套的 Go 包。包的主要目的是帮助你将相关的源文件组织到一个单元中,使它们更易于复用和维护。

每个 Go 源文件都属于一个包;这就是为什么每个 Go 文件都以包声明开头:

go 复制代码
package packagename

源文件中的任何变量、类型或函数都属于其声明的包,同一个包内的其他源文件都可以访问。

存在于同一目录中的 Go 源文件必须属于同一个包。尽管不强制要求包的名称与其所在目录同名,但遵循这个约定是一个好习惯。

导入包

最常用的内置 Go 包之一是提供 I/O 功能的 fmt 包。要在代码中使用这个包,你可以在包声明下方导入它:

go 复制代码
package packagename

import "fmt"

导入 fmt 包后,你就可以访问该包导出的函数。你可以使用点 . 操作符来访问这些函数,例如 fmt.Println()fmt.Scanf()

通常,你的程序中会需要使用多个包。你可以使用以下语法导入多个包:

go 复制代码
import (
    "fmt"
    "math"
    "strings"
)

在少数情况下,例如调试未完成的代码时,代码中可能会有一些未使用的包。为了避免编译器报错,你可以在包名前使用空白标识符 _。例如:

go 复制代码
import (
    "fmt"
    "math"
    _ "os"
    "strings"
)

_的另一个作用是触发某些包中的初始化 init() 函数。例如,在使用数据库驱动时,你可以使用空白导入来触发 init() 函数,为该包提供操作数据库所需的数据。请看下面使用 Go 连接 PostgreSQL 数据库的例子:

go 复制代码
import (
    "database/sql" // 导入 Go 的 database/sql 包

    _ "github.com/lib/pq" // 导入 database/sql 包所需的 PostgreSQL sql 驱动
)

github.com/lib/pq 包中,conn.go 文件包含了 init() 函数。简单来说,这将把必要的数据传递给主包中的 database/sql 包,使其能够与 PostgreSQL 数据库协同工作:

go 复制代码
func init() {
    // 当使用 "_" 导入初始化时,init() 函数会将必要数据
    // 传递给主包中的 database/sql 包,使其能够与 PostgreDB 协同工作
    sql.Register("postgres", &Driver{})
}

另一种特殊的导入方式是点 . 导入。它将包导入到当前包相同的命名空间中,因此无需使用导入包的名字来访问其函数。例如:

go 复制代码
import (
    . "fmt"
    . "math"
)

func main() {
    // 向控制台输出 5,你可以直接使用 Println 而无需加 fmt. 前缀,Abs 也无需加 math. 前缀
    Println(Abs(-5))
}

你也可以导入嵌套包,例如:

go 复制代码
import "math/rand"

这里 math 是主包,rand 是嵌套包。在这种情况下,你只能使用 rand 包内的函数,math 包的其他任何功能都不可用,除非你同时导入了 mathmath/rand 包。

作为一个良好的编码实践,请记住只导入你将在代码中使用的包!否则,你会得到 imported and not used(已导入但未使用)的编译错误。

包的类型

Go 中有两种类型的包:可执行包和工具包。可执行包包含一个可由 Go 编译运行的可执行程序。而工具包本身不可执行;它只包含可在可执行包中使用的工具函数。fmtosmath 等就是工具包的例子。

一个特殊的可执行包是 main 包。要在 Go 中创建可执行包,有两个要求:

  1. 包的名称必须是 main

  2. 它应该包含一个名为 main() 的函数,这将是程序的起点。

下面你可以看到位于 main 包中的源文件 main.go 的内容:

go 复制代码
package main

import "fmt"

func main() {
    fmt.Println("Hello World!")
}

外部包

你也可以使用 go get 命令将外部包安装到你的项目中。例如,让我们尝试安装托管在 GitHub 上的 fatih/color 包:

bash 复制代码
$ go get github.com/fatih/color

从 Go 1.16 版本开始,模块感知模式默认启用。因此,如果你使用 Go 1.16 或更高版本,并想安装外部包,需要执行以下步骤:

  1. 在终端中执行 go mod init module-name 命令在项目中初始化 Go 模块,例如 go mod init example

  2. 然后执行 go get package-name 命令来安装外部包,例如 go get github.com/fatih/color

  3. 最后,执行 go mod tidy 命令来添加缺失的模块并移除项目中未使用的模块。

现在你可以在 main.go 文件中导入 fatih/color 包了:

go 复制代码
package main

import "github.com/fatih/color"

func main() {
    color.Red("Hello World!")
}

执行 go run main.go 后,你将在终端中看到以下红色输出:

text 复制代码
Hello World!

内部包

最后但同样重要的是,你也可以创建内部包。内部包很特殊,因为它们必须位于项目内名为 internal 的目录中。

Go 工具能识别这个 internal 目录,并防止它包含的包被任何不共享同一父目录或不是该父目录子目录的包导入。

例如,让我们看一下包含嵌套内部包的 example 目录结构:

go 复制代码
├── calculator
│   ├── calculator.go
│   └── internal
│       └── modulo.go
└── main
    └── main.go

example/calculator/internal 这个内部包可以被 calculator.goexample/calculator 目录及其子目录内的任何其他 Go 源文件导入,因为它们共享共同的父目录 example/calculator

然而,如果你尝试从位于 example/main 目录的 main 包导入 example/calculator/internal 包,将会得到以下编译错误:

go 复制代码
use of internal package example/calculator/internal not allowed

这是因为 example/main 目录和 example/calculator/internal 目录 共享共同的父目录 example/calculator

总结

  • Go 包就是一个包含相关 Go 源文件的目录;

  • Go 中有两种类型的包:工具包和可执行包。工具包不可执行;它们只包含可供可执行的 main 包使用的函数,main 包是程序的入口点;

  • 你可以通过 go get 命令将外部包安装到你的项目中;

  • 内部包是一种特殊类型的包,必须始终位于名为 internal 的目录内。请记住,内部包只能由位于与该内部包相同父目录或其子目录内的包导入。

相关推荐
JustHappy4 小时前
古法编程秘籍(七):互联网到底是什么?把两台电脑怎么说话搞懂就够了
前端·后端·网络协议
yaoxin5211235 小时前
434. Java 日期时间 API - Period 基于日期的时间段
java·开发语言·python
Hommy885 小时前
【剪映小助手】添加图片接口(Add Images)
后端·github·剪映小助手·视频剪辑自动化
凡人叶枫5 小时前
Effective C++ 条款30:透彻了解 inlining 的里里外外
linux·开发语言·c++·嵌入式开发·effective c++
GetcharZp5 小时前
别再盲目用 OpenCV 读图了,这才是 CV 预处理的终极杀手锏!
后端
学逆向的5 小时前
C++纯虚函数
开发语言·c++·网络安全
程序员二叉6 小时前
【JUC】ThreadLocal底层原理|内存泄漏|弱引用|跨线程传递方案
java·开发语言·面试·职场和发展·juc
程序员二叉6 小时前
【JUC】线程池全套深度详解|参数|流程|拒绝策略|调优|异常处理
java·开发语言·jvm·算法·面试·juc
凡人叶枫7 小时前
Effective C++ 条款22:将成员变量声明为 private
linux·开发语言·c++
Qt程序员7 小时前
掌握 Linux 内核调度:从原理到实现(进程篇)
java·开发语言