Skip to content

包和模块

Go 语言的包系统是其组织代码的核心机制,而 Go Modules 是现代 Go 项目的依赖管理方式。

包(Package)

包的概念

包是 Go 语言中代码组织和复用的基本单位。每个 Go 文件都属于一个包。

go
package main  // 包声明

import "fmt"  // 导入包

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

包声明

  • package main: 可执行程序的入口包
  • package <name>: 库包,可以被其他包导入

导入包

go
// 单个导入
import "fmt"

// 多个导入
import (
    "fmt"
    "os"
    "strings"
)

// 别名导入
import f "fmt"
f.Println("Hello")

// 点导入(不推荐)
import . "fmt"
Println("Hello")

// 空白导入(只执行 init 函数)
import _ "database/sql/driver"

Go Modules

Go Modules 是 Go 1.11+ 引入的官方依赖管理工具。

初始化模块

bash
go mod init <module-name>

这会创建 go.mod 文件:

go
module github.com/user/project

go 1.21

require (
    github.com/go-zoox/zoox v1.x.x
)

添加依赖

bash
# 自动添加依赖
go get github.com/go-zoox/zoox

# 指定版本
go get github.com/go-zoox/zoox@v1.x.x

# 最新版本
go get github.com/go-zoox/zoox@latest

go.mod 文件

go
module github.com/user/project

go 1.21

require (
    github.com/go-zoox/zoox v1.x.x
    github.com/stretchr/testify v1.8.4
)

require (
    github.com/go-zoox/core-utils v1.x.x // indirect
)

go.sum 文件

go.sum 文件包含依赖的校验和,用于验证依赖的完整性。

常用命令

bash
# 下载依赖
go mod download

# 整理依赖
go mod tidy

# 查看依赖
go list -m all

# 更新依赖
go get -u ./...

# 验证依赖
go mod verify

包的可见性

Go 语言使用首字母大小写控制可见性:

go
// 公开(可被其他包访问)
func PublicFunction() {}

var PublicVariable = "public"

// 私有(只能在当前包内访问)
func privateFunction() {}

var privateVariable = "private"

包的组织

标准项目结构

project/
├── go.mod
├── go.sum
├── main.go
├── cmd/
│   └── server/
│       └── main.go
├── internal/
│   ├── config/
│   └── handler/
├── pkg/
│   ├── utils/
│   └── models/
└── api/
    └── routes.go

internal 包

internal 目录下的包只能被父目录的包导入:

project/
├── internal/
│   └── auth/     # 只能被 project 下的包导入
└── pkg/
    └── utils/    # 可以被任何包导入

导入和导出

导出函数

go
// package math
package math

// Add 是导出的函数
func Add(a, b int) int {
    return a + b
}

// subtract 是未导出的函数
func subtract(a, b int) int {
    return a - b
}

使用导出的函数

go
package main

import "github.com/user/project/math"

func main() {
    result := math.Add(1, 2)  // OK
    // math.subtract(1, 2)     // 错误:未导出
}

init 函数

每个包可以有一个或多个 init 函数,在包被导入时自动执行:

go
package config

var Config map[string]string

func init() {
    Config = make(map[string]string)
    Config["env"] = "production"
}

标准库介绍

常用标准库

fmt

格式化输入输出:

go
import "fmt"

fmt.Print("Hello")
fmt.Println("World")
fmt.Printf("Name: %s, Age: %d\n", name, age)

os

操作系统接口:

go
import "os"

// 环境变量
os.Getenv("PATH")
os.Setenv("KEY", "value")

// 文件操作
os.Open("file.txt")
os.Create("file.txt")

strings

字符串操作:

go
import "strings"

strings.Contains("hello", "ll")
strings.Split("a,b,c", ",")
strings.Join([]string{"a", "b"}, ",")
strings.TrimSpace("  hello  ")

net/http

HTTP 客户端和服务器:

go
import "net/http"

// HTTP 服务器
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)

// HTTP 客户端
resp, err := http.Get("https://example.com")

encoding/json

JSON 编码和解码:

go
import "encoding/json"

type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

data, _ := json.Marshal(Person{Name: "Alice", Age: 30})
var p Person
json.Unmarshal(data, &p)

time

时间处理:

go
import "time"

now := time.Now()
duration := time.Hour * 2
future := now.Add(duration)

sync

同步原语:

go
import "sync"

var mutex sync.Mutex
var wg sync.WaitGroup
var once sync.Once

创建自己的包

包结构

mypackage/
├── go.mod
├── math.go
└── utils.go

math.go

go
package mypackage

// Add 两个数相加
func Add(a, b int) int {
    return a + b
}

// Multiply 两个数相乘
func Multiply(a, b int) int {
    return a * b
}

使用包

go
package main

import "github.com/user/mypackage"

func main() {
    sum := mypackage.Add(1, 2)
    product := mypackage.Multiply(3, 4)
}

版本管理

语义化版本

Go Modules 使用语义化版本(Semantic Versioning):

  • v1.2.3: 主版本.次版本.修订版本
  • v0.1.0: 开发版本
  • v1.0.0-beta.1: 预发布版本

版本选择

go
require (
    github.com/go-zoox/zoox v1.x.x  // 精确版本
    github.com/go-zoox/zoox ^1.0.0  // 兼容版本
    github.com/go-zoox/zoox latest  // 最新版本
)

完整示例

go
// go.mod
module github.com/user/mylib

go 1.21

// math/math.go
package math

// Add 返回两个整数的和
func Add(a, b int) int {
    return a + b
}

// Subtract 返回两个整数的差
func Subtract(a, b int) int {
    return a - b
}

// main.go
package main

import (
    "fmt"
    "github.com/user/mylib/math"
)

func main() {
    sum := math.Add(10, 5)
    diff := math.Subtract(10, 5)
    
    fmt.Printf("和: %d, 差: %d\n", sum, diff)
}

最佳实践

  1. 使用有意义的包名:简短、小写、单数形式
  2. 避免循环依赖:合理组织包结构
  3. 使用 internal 包:限制内部包的可见性
  4. 保持包的精简:每个包应该有单一职责
  5. 使用 go mod tidy:定期整理依赖

下一步

接下来我们将学习:

基于 VitePress 构建