引入
代码越写越多,全塞在一个文件里肯定不行。Go 用包(package)把代码按功能组织在一起,方便复用和管理。每个 .go 文件都必须属于一个包,包和包之间通过导入来使用对方的代码。
正文
定义
定义
包(package)是 Go 代码的组织单元,把代码按功能组织在一起,方便复用和管理。每个
.go文件的第一行必须声明所属包名。大写开头的标识符是导出的(外部可用),小写开头的标识符是未导出的(仅包内可用)。
语法
// 声明包(每个文件第一行必须有)
package mypackage
// 导入其他包
import "fmt"
import "math/rand"
// 批量导入
import (
"fmt"
"os"
"strings"
)
// 导出函数(大写开头)
func Hello() string {
return "hello"
}
// 未导出函数(小写开头)
func helper() string {
return "helper"
}例子
创建自定义包
project/
├── main.go
└── greeting/
└── greeting.go
// greeting/greeting.go
package greeting
func Hello(name string) string {
return "Hello, " + name
}
func hi(name string) string {
return "Hi, " + name // 小写开头,外部不能调用
}// main.go
package main
import (
"fmt"
"project/greeting"
)
func main() {
fmt.Println(greeting.Hello("Alice"))
// fmt.Println(greeting.hi("Alice")) // 编译错误:未导出
}大写开头的 Hello 能被外部包调用,小写开头的 hi 只能在 greeting 包内部使用。
导入路径
// 标准库包
import "fmt"
import "os"
import "net/http"
// 第三方包
import "github.com/gin-gonic/gin"
// 项目内部包
import "project/internal/utils"标准库直接用包名导入,第三方包和项目内部包用完整路径。
包的别名
import (
"fmt"
myrand "math/rand"
)
func main() {
fmt.Println(myrand.Intn(100))
}用 别名 包路径 的语法给导入的包起个别名,解决包名冲突或起一个更短的名字。
点导入
import . "fmt"
func main() {
Println("hello") // 不需要 fmt. 前缀
}点导入后可以直接用包里的标识符,不需要加包名前缀。不推荐使用,会降低代码可读性。
空白导入
import _ "net/http/pprof"空白导入 _ 不直接使用包的内容,但会执行包的 init() 函数。常用于注册驱动或启动副作用。
init() 函数
package config
import "fmt"
var AppName string
func init() {
AppName = "MyApp"
fmt.Println("config 包初始化完成")
}init() 函数在包被导入时自动执行,不需要手动调用。常用来做包的初始化工作。
init() 执行顺序
package main
import "fmt"
var x = initVar()
func initVar() int {
fmt.Println("变量初始化")
return 1
}
func init() {
fmt.Println("init 函数")
}
func main() {
fmt.Println("main 函数")
}
// 输出顺序:
// 变量初始化
// init 函数
// main 函数执行顺序:变量初始化 → init() → main()。同一个包里可以有多个 init() 函数,按文件名字母序执行。
常见写法
| 写法 | 说明 |
|---|---|
package name | 声明包名(文件第一行) |
import "path" | 导入包 |
import ( "a"; "b" ) | 批量导入 |
import alias "path" | 导入并起别名 |
import . "path" | 点导入(不推荐) |
import _ "path" | 空白导入(只执行 init) |
func init() | 包初始化函数 |
大写开头 | 导出(外部可用) |
小写开头 | 未导出(仅包内可用) |
特点
- 每个
.go文件第一行必须声明包名 - 大写开头的标识符是导出的,小写开头的未导出
- 包名通常和目录名一致,用小写短单词
import路径是目录路径,不是包名init()自动执行,适合做包的初始化- 执行顺序:变量初始化 →
init()→main() - 同一个包可以有多个文件,同包内标识符互相可见
main包是可执行程序的入口,只有main包有main()函数
理解
包就是把代码按功能分到不同抽屉里,大写的东西能给别人用,小写的自己留着。import 告诉 Go 去哪个抽屉拿东西,init() 在打开抽屉时自动跑一次。包是 Go 组织代码的基础,理解了包才能看懂 Go 项目是怎么管理的。
引出
包解决了代码组织问题,但项目大了以后,怎么管理外部依赖?不同项目用了不同版本的第三方包怎么办?接下来看 Go 模块,学习 Go 的依赖管理方案。