Go语言第十八章(架构设计)

Go Modules

前面写的都是「单文件 package main」。真正做项目时,代码要拆成多个包、依赖要版本可控------这就靠 Go Modules。

本篇按动手顺序来:

  1. go mod init 建模块
  2. go mod tidy 整理依赖
  3. 自定义包和导入路径
  4. 大写导出 / 小写私有
  5. cmd、internal、pkg 简单目录
  6. 引入一个第三方依赖演示

1. go mod init:创建模块

在空目录里初始化:

bash 复制代码
mkdir hello-mod
cd hello-mod
go mod init example.com/hello

会生成 go.mod:

go 复制代码
module example.com/hello

go 1.26.4
字段 含义
module example.com/hello 模块路径,也是包的导入前缀
go 1.22 本模块使用的 Go 语言版本

模块路径习惯写成「能当导入前缀」的名字,常见两种:

  • 学习演示:example.com/hello、myapp
  • 真仓库:github.com/你的用户名/仓库名

go.mod 管的是整个模块(一个仓库通常一个),不是每个子目录一个。


2. go mod tidy:整理依赖

写完代码、增删 import 之后执行:

bash 复制代码
go mod tidy

它会:

  • 把代码里真正用到 的依赖写进 go.mod,并生成/更新 go.sum(校验和)
  • 删掉已经不用的依赖

记住分工:

命令 什么时候用
go mod init 项目一开始,只跑一次
go mod tidy 改过 import / 依赖后,随时跑

go.sum 不要手改,提交到 Git 即可,用来保证大家下到同一份依赖。


3. 自定义包和导入路径

目录名 ≈ 包名;导入路径 = 模块路径 + 子目录。

text 复制代码
hello-mod/
├── go.mod                 # module example.com/hello
├── main.go                # package main
└── greet/
    └── greet.go           # package greet

greet/greet.go:

go 复制代码
package greet

import "fmt"

func Hello(name string) {
	fmt.Println("你好,", name)
}

根目录 main.go:

go 复制代码
package main

import "example.com/hello/greet" // 模块路径 + 子目录

func main() {
	greet.Hello("小满")
}

运行:

bash 复制代码
go run .
# 你好, 小满

要点:

  • 导入写的是路径 ,不是文件名:example.com/hello/greet
  • 调用时用包名 :greet.Hello(...)(一般等于最后一级目录名)
  • 同一个目录里所有 .go 必须是同一个 package 名

4. 大写导出 / 小写私有

Go 没有 public / private 关键字,靠首字母大小写:

写法 可见范围
Hello、User、MaxRetry 导出:别的包可以访问
hello、user、maxRetry 未导出:仅本包内部可用
go 复制代码
package greet

import "fmt"

// 导出:外部可调用
func Hello(name string) {
	fmt.Println(prefix(), name)
}

// 未导出:外部写 greet.prefix() 会编译失败
func prefix() string {
	return "你好,"
}

外面只能:

go 复制代码
greet.Hello("小满") // OK
// greet.prefix()  // 报错:prefix 未导出

结构体字段同样规则:Name 导出,age 仅包内可见(JSON 标签、跨包赋值都会受影响)。


5. cmd、internal、pkg 简单目录

小项目一个 greet 包就够。稍大一点,社区常见这种骨架:

text 复制代码
hello-mod/
├── go.mod
├── cmd/
│   └── hello/
│       └── main.go      # 可执行入口:go run ./cmd/hello
├── internal/
│   └── auth/
│       └── auth.go      # 仅本模块能导入(编译器强制)
└── pkg/
    └── greeter/
        └── greeter.go   # 可被外部模块导入的库代码
目录 放什么 谁能 import
cmd/<名字>/ package main,程序入口 不作为库被导入,用来 go build / go run
internal/... 模块内部实现 只有本模块 (及 internal 的父树)能导入;外人导入会编译失败
pkg/... 打算给别人用的库 任意模块都可导入

cmd/hello/main.go 示例:

go 复制代码
package main

import (
	"example.com/hello/internal/auth"
	"example.com/hello/pkg/greeter"
)

func main() {
	auth.Check()
	greeter.Hello("小满")
}

internal/auth/auth.go:

go 复制代码
package auth

import "fmt"

func Check() {
	fmt.Println("auth ok")
}

pkg/greeter/greeter.go:

go 复制代码
package greeter

import "fmt"

func Hello(name string) {
	fmt.Println("你好,", name)
}

说明:

  • internal 是语言级约定:别的仓库 import "example.com/hello/internal/auth" 会直接报错
  • pkg 不是强制的,很多项目把可导出库直接放在模块根下;放 pkg 只是「这里是对外 API」更清晰
  • 入门项目不必硬套三层;有多个可执行文件再用 cmd,有不想被外人用的代码再放 internal

6. 引入第三方依赖演示

先配置国内代理(重要)

默认的官方代理 proxy.golang.org 在国内经常超时或拉不下来。拉第三方库之前,建议先把模块代理改成国内镜像。

推荐使用七牛云维护的 goproxy.cn:

bash 复制代码
# 永久生效(推荐)
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct

验证是否设置成功:

bash 复制代码
go env GOPROXY
# 应输出:https://goproxy.cn,direct

说明:

写法 含义
https://goproxy.cn 优先走国内代理下载模块
,direct 代理没有时,再直连源站(如 GitHub)

也可以临时设置(只对当前终端有效):

bash 复制代码
# Windows PowerShell
$env:GOPROXY = "https://goproxy.cn,direct"

# macOS / Linux
export GOPROXY=https://goproxy.cn,direct

其他可选镜像(备用):

代理地址 说明
https://goproxy.cn,direct 首选,七牛云,国内最常用
https://proxy.golang.com.cn,direct 官方域名的国内镜像站
https://goproxy.io,direct 另一家公共代理

公司私有仓库不要走公共代理时,可再加:

bash 复制代码
go env -w GOPRIVATE=git.公司域名.com

演示:安装并使用第三方库

以常用的颜色输出库 github.com/fatih/color 为例。

在 main.go(或 cmd/hello/main.go)里先写上 import 和用法:

go 复制代码
package main

import (
	"github.com/fatih/color"
)

func main() {
	color.Green("go mod 依赖引入成功")
	color.Red("这是红色警告")
}

然后拉依赖并整理:

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

go.mod 里会出现类似:

go 复制代码
module example.com/hello

go 1.22

require github.com/fatih/color v1.18.0

再运行:

bash 复制代码
go run .
# 终端里会看到绿色 / 红色文字

常用依赖命令:

命令 作用
go get 路径@版本 添加或升级某个依赖,如 @v1.18.0、@latest
go mod tidy 按实际 import 增删依赖
go list -m all 查看当前模块解析到的依赖树

换依赖时:改代码里的 import → go get(可选)→ go mod tidy。


小结

主题 记住什么
go mod init 定模块路径,生成 go.mod
go mod tidy 按代码同步依赖与 go.sum
导入路径 模块路径 + 子目录
导出规则 大写对外,小写包内
cmd / internal / pkg 入口 / 私有实现 / 对外库
第三方库 先配 GOPROXY=https://goproxy.cn,direct,再 go get + import + tidy

最小心智模型:

一个 go.mod = 一个模块;一个目录 = 一个包;导入靠路径,可见性靠大小写。

相关推荐
山甫aa22 分钟前
锁一篇搞定:乐观锁、悲观锁、CAS、数据库锁与分布式锁【从零开始的 Web 后端学习】
java·数据库·分布式·后端·学习·web
IT_陈寒1 小时前
Java开发实战:从入门到精通
前端·人工智能·后端
jktantan1 小时前
注解式脱敏:用 Jackson 的 ContextualSerializer 做字段级策略(一)
spring boot·后端·算法·spring cloud·系统架构
独泪了无痕10 小时前
探索Pinyin4j-Java中的拼音转换利器
java·后端
码事漫谈10 小时前
从 Coze 居然要下线了说起
后端
想不到一个好的ID11 小时前
智能体开发
后端
皮皮林55111 小时前
为什么数据库连接池不采用 IO 多路复用?
后端
IT_陈寒15 小时前
Redis雪崩把我坑惨了,这是5年经验的教训
前端·人工智能·后端
量化分析码农15 小时前
【Python量化多因子实战 06】从因子到持仓:多因子选股实盘工程化落地
后端