目錄
Go 專案目錄結構
標準專案結構
myproject/
├── cmd/ # 主要應用程式入口
│ ├── server/ # 伺服器應用程式
│ │ └── main.go # 伺服器入口
│ └── cli/ # CLI 工具
│ └── main.go # CLI 入口
├── internal/ # 私有程式碼(不可被外部 import)
│ ├── auth/ # 認證邏輯
│ ├── database/ # 資料庫相關
│ └── service/ # 業務邏輯
├── pkg/ # 公開程式碼(可被外部 import)
│ ├── utils/ # 工具函數
│ └── models/ # 資料模型
├── api/ # API 定義檔案
│ ├── openapi.yaml # OpenAPI 規格
│ └── protobuf/ # Protocol Buffers 定義
├── web/ # Web 靜態資源
│ ├── static/ # 靜態檔案
│ └── templates/ # 模板檔案
├── configs/ # 配置檔案
│ ├── config.yaml
│ └── config.json
├── scripts/ # 建構與部署腳本
│ ├── build.sh
│ └── deploy.sh
├── test/ # 額外的測試檔案
│ └── integration/ # 整合測試
├── docs/ # 文件
│ └── README.md
├── vendor/ # 第三方依賴(使用 go mod vendor)
├── .gitignore # Git 忽略檔案
├── go.mod # Go 模組定義
├── go.sum # 依賴校驗和
├── Makefile # 建構指令
└── README.md # 專案說明
目錄說明
/cmd - 應用程式入口
// cmd/server/main.go
package main
import "fmt"
func main() {
fmt.Println("伺服器啟動")
}
用途:
- 存放專案的主要應用程式
- 每個子目錄代表一個可執行程式
- 目錄名稱應該與執行檔名稱一致
命名規則:
cmd/server/→ 產生server執行檔cmd/myapp/→ 產生myapp執行檔
/internal - 私有程式碼
// internal/auth/auth.go
package auth
// 此套件只能被本專案內部使用
func ValidateToken(token string) bool {
// 驗證邏輯
return true
}
特性:
- Go 編譯器會強制這個目錄下的程式碼不被外部 import
- 只有同一個專案內的程式碼可以使用
- 適合放私有的業務邏輯
範例:
myproject/internal/auth ✅ 可被 myproject 使用
otherproject/ ❌ 無法 import myproject/internal/auth
/pkg - 公開程式碼
// pkg/utils/string.go
package utils
// 可以被外部專案 import
func Capitalize(s string) string {
// 實作
return s
}
用途:
- 存放可以被外部專案使用的程式碼
- 提供公開的 API 或工具函數
- 通常用於開發可重用的套件
使用時機:
- 工具函數(utils)
- 共用模型(models)
- 公開的 API 客戶端
/api - API 定義
api/
├── openapi.yaml # REST API 定義
├── protobuf/ # gRPC 定義
│ └── user.proto
└── graphql/ # GraphQL schema
└── schema.graphql
用途:
- API 規格定義
- Protocol Buffers (.proto)
- OpenAPI/Swagger 定義
/configs - 配置檔案
# configs/config.yaml
server:
port: 8080
host: localhost
database:
host: localhost
port: 5432
用途:
- 應用程式配置
- 環境變數範本
- 不應包含敏感資訊(密碼、金鑰)
/scripts - 建構腳本
#!/bin/bash
# scripts/build.sh
echo "開始建構..."
go build -o bin/server cmd/server/main.go
echo "建構完成"
用途:
- 建構腳本
- 部署腳本
- 資料庫遷移腳本
/test - 測試檔案
test/
├── integration/ # 整合測試
│ └── api_test.go
├── e2e/ # 端到端測試
│ └── workflow_test.go
└── fixtures/ # 測試資料
└── testdata.json
注意:
- 單元測試通常放在與原始碼同一目錄(
*_test.go) - 此目錄主要用於額外的測試類型
/vendor - 第三方依賴
vendor/
├── github.com/
│ └── gin-gonic/gin/
└── golang.org/x/
└── crypto/
用途:
- 存放專案依賴的副本
- 使用
go mod vendor產生 - 確保建構的可重現性
何時使用:
- 需要離線建構
- 確保依賴版本固定
- CI/CD 環境
簡化的小型專案結構
simple-project/
├── main.go # 單一入口
├── handler.go # HTTP 處理器
├── model.go # 資料模型
├── go.mod # 模組定義
├── go.sum # 依賴校驗
└── README.md
重要檔案說明
go.mod - 模組定義檔
module github.com/username/myproject
go 1.21
require (
github.com/gin-gonic/gin v1.9.1
gorm.io/gorm v1.25.5
)
require (
github.com/bytedance/sonic v1.9.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
)
replace github.com/old/package => github.com/new/package v1.2.3
各部分說明:
1. module - 模組路徑
module github.com/username/myproject
- 定義模組的唯一識別路徑
- 通常使用 GitHub 倉庫路徑
- 其他人可以透過此路徑 import 你的專案
2. go - Go 版本
go 1.21
- 指定所需的最低 Go 版本
- 影響語言特性的可用性
3. require - 直接依賴
require (
github.com/gin-gonic/gin v1.9.1
gorm.io/gorm v1.25.5
)
- 專案直接使用的套件
- 指定版本號(使用語義化版本)
4. require (indirect) - 間接依賴
require (
github.com/bytedance/sonic v1.9.1 // indirect
)
- 依賴的套件所需要的套件
- 由 Go 自動管理
5. replace - 替換依賴
replace github.com/old/package => github.com/new/package v1.2.3
- 替換特定依賴的來源
- 用於修復依賴、本地開發
使用情境:
// 使用本地版本開發
replace github.com/myorg/mylib => ../mylib
// 修復有問題的依賴
replace github.com/broken/lib => github.com/fixed/lib v1.0.0
go.sum - 依賴校驗和檔
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
用途:
- 記錄每個依賴的加密雜湊值(SHA-256)
- 確保依賴的完整性和一致性
- 防止依賴被篡改
特性:
- 自動產生和更新(不應手動編輯)
- 應該提交到版本控制系統
- 每個依賴有兩行:模組本身 + go.mod 檔案
.gitignore - Git 忽略檔案
# 執行檔
*.exe
*.exe~
*.dll
*.so
*.dylib
/bin/
/dist/
# 測試覆蓋率
*.out
coverage.txt
# 編譯器產生的檔案
*.o
*.a
*.so
# IDE
.idea/
.vscode/
*.swp
*.swo
# 環境變數
.env
.env.local
# 作業系統
.DS_Store
Thumbs.db
# Go workspace 檔案
go.work
go.work.sum
# 依賴(如果使用 vendor)
# vendor/
Go Modules 模組管理
什麼是 Go Modules?
Go Modules 是 Go 官方的依賴管理系統(Go 1.11+ 引入,1.16+ 預設啟用)
核心概念:
- Module(模組):一組相關 Go 套件的集合
- 版本控制:使用語義化版本(Semantic Versioning)
- 可重現建構:確保每次建構使用相同的依賴版本
語義化版本
v1.2.3
│ │ │
│ │ └─ Patch:修復 bug(向後相容)
│ └─── Minor:新增功能(向後相容)
└───── Major:重大變更(可能不相容)
範例:
v1.0.0→v1.0.1:修復 bugv1.0.0→v1.1.0:新增功能v1.9.9→v2.0.0:API 重大變更
版本選擇規則
require (
github.com/gin-gonic/gin v1.9.1 // 精確版本
github.com/gin-gonic/gin v1.9 // 最新的 1.9.x
github.com/gin-gonic/gin latest // 最新版本(不推薦)
)
最佳實踐:
- 生產環境使用精確版本號
- 開發階段可以使用
latest取得最新版本
Go 指令詳解
1. go mod - 模組管理
go mod init - 初始化模組
# 建立新模組
go mod init github.com/username/myproject
# 建立本地模組
go mod init myproject
作用:
- 建立
go.mod檔案 - 定義模組路徑
go mod tidy - 整理依賴
go mod tidy
作用:
- 新增缺少的依賴
- 移除未使用的依賴
- 更新
go.sum
使用時機:
- 新增或刪除 import 後
- 定期清理專案依賴
go mod download - 下載依賴
go mod download
作用:
- 下載所有依賴到本地快取
- 不修改
go.mod或go.sum
使用時機:
- CI/CD 環境預先下載依賴
- 離線工作前準備依賴
go mod vendor - 建立 vendor 目錄
go mod vendor
作用:
- 將依賴複製到
vendor/目錄 - 確保離線建構
建構時使用:
go build -mod=vendor
go mod verify - 驗證依賴
go mod verify
作用:
- 檢查依賴的完整性
- 確認下載的模組未被修改
go mod graph - 顯示依賴圖
go mod graph
輸出範例:
github.com/username/myproject github.com/gin-gonic/gin@v1.9.1
github.com/gin-gonic/gin@v1.9.1 github.com/bytedance/sonic@v1.9.1
go mod why - 解釋依賴原因
# 為什麼需要這個套件?
go mod why github.com/bytedance/sonic
輸出範例:
# github.com/bytedance/sonic
github.com/username/myproject
github.com/gin-gonic/gin
github.com/bytedance/sonic
2. go get - 新增/更新依賴
新增依賴
# 新增最新版本
go get github.com/gin-gonic/gin
# 新增特定版本
go get github.com/gin-gonic/gin@v1.9.1
# 新增特定分支
go get github.com/gin-gonic/gin@master
# 新增特定 commit
go get github.com/gin-gonic/gin@abc1234
更新依賴
# 更新到最新版本
go get -u github.com/gin-gonic/gin
# 更新所有依賴
go get -u ./...
# 更新 patch 版本(如 v1.9.0 → v1.9.1)
go get -u=patch github.com/gin-gonic/gin
移除依賴
# 移除依賴(不會自動刪除 import)
go get github.com/old/package@none
# 然後執行 tidy 清理
go mod tidy
3. go build - 建構程式
基本用法
# 建構當前目錄
go build
# 建構並指定輸出檔名
go build -o myapp
# 建構特定檔案
go build main.go
# 建構特定套件
go build ./cmd/server
進階選項
# 交叉編譯(Linux)
GOOS=linux GOARCH=amd64 go build -o myapp-linux
# 交叉編譯(Windows)
GOOS=windows GOARCH=amd64 go build -o myapp.exe
# 交叉編譯(macOS)
GOOS=darwin GOARCH=arm64 go build -o myapp-mac
# 縮小執行檔大小
go build -ldflags="-s -w" -o myapp
# 加入版本資訊
go build -ldflags="-X main.Version=1.0.0" -o myapp
常用平台組合:
| 作業系統 | GOOS | GOARCH |
|---|---|---|
| Linux 64-bit | linux | amd64 |
| Windows 64-bit | windows | amd64 |
| macOS Intel | darwin | amd64 |
| macOS Apple Silicon | darwin | arm64 |
| Raspberry Pi | linux | arm |
4. go run - 執行程式
# 執行單一檔案
go run main.go
# 執行多個檔案
go run main.go helper.go
# 執行套件
go run ./cmd/server
# 傳遞參數
go run main.go -port=8080
注意:
go run會編譯並立即執行- 不會產生執行檔
- 適合開發和測試
5. go test - 執行測試
基本用法
# 執行當前目錄測試
go test
# 執行所有測試
go test ./...
# 詳細輸出
go test -v
# 執行特定測試函數
go test -run TestUserLogin
# 執行特定套件
go test ./internal/auth
測試覆蓋率
# 顯示覆蓋率
go test -cover
# 產生覆蓋率報告
go test -coverprofile=coverage.out
# 查看覆蓋率報告(HTML)
go tool cover -html=coverage.out
效能測試(Benchmark)
# 執行 benchmark
go test -bench=.
# 指定執行時間
go test -bench=. -benchtime=10s
# 包含記憶體分配統計
go test -bench=. -benchmem
6. go install - 安裝工具
# 安裝工具到 $GOPATH/bin
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# 安裝本地套件
go install ./cmd/myapp
安裝位置:
$GOPATH/bin(通常是~/go/bin)- 需要將此目錄加入
PATH
7. go fmt - 格式化程式碼
# 格式化當前目錄
go fmt
# 格式化所有程式碼
go fmt ./...
# 格式化特定檔案
go fmt main.go
作用:
- 統一程式碼風格
- 自動調整縮排、空格
8. go vet - 靜態分析
# 檢查當前目錄
go vet
# 檢查所有程式碼
go vet ./...
檢查項目:
- 可疑的程式碼結構
- 常見錯誤(如 Printf 格式錯誤)
- 不正確的函數簽名
9. go doc - 查看文件
# 查看套件文件
go doc fmt
# 查看函數文件
go doc fmt.Println
# 查看本地套件
go doc ./internal/auth
# 啟動文件伺服器
go doc -http=:6060
10. go clean - 清理建構檔案
# 清理建構快取
go clean
# 清理所有快取
go clean -cache
# 清理測試快取
go clean -testcache
# 清理模組快取
go clean -modcache
11. go list - 列出套件資訊
# 列出所有套件
go list ./...
# 列出依賴
go list -m all
# 以 JSON 格式輸出
go list -json
12. go env - 環境變數
# 顯示所有環境變數
go env
# 顯示特定變數
go env GOPATH
# 設定環境變數
go env -w GOPROXY=https://goproxy.io,direct
常用環境變數:
GOPATH:Go 工作區路徑GOROOT:Go 安裝路徑GOPROXY:模組代理GOPRIVATE:私有模組路徑
實際範例
範例 1:建立新專案
# 1. 建立專案目錄
mkdir myproject
cd myproject
# 2. 初始化模組
go mod init github.com/username/myproject
# 3. 建立主程式
cat > main.go << 'EOF'
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "Hello World"})
})
r.Run(":8080")
}
EOF
# 4. 新增依賴
go get github.com/gin-gonic/gin
# 5. 整理依賴
go mod tidy
# 6. 執行
go run main.go
範例 2:建立標準專案結構
#!/bin/bash
PROJECT_NAME="myapp"
GITHUB_USER="username"
# 建立目錄結構
mkdir -p $PROJECT_NAME/{cmd/server,internal/{auth,database,service},pkg/utils,configs,scripts,docs}
cd $PROJECT_NAME
# 初始化模組
go mod init github.com/$GITHUB_USER/$PROJECT_NAME
# 建立主程式
cat > cmd/server/main.go << 'EOF'
package main
import "fmt"
func main() {
fmt.Println("Server starting...")
}
EOF
# 建立 .gitignore
cat > .gitignore << 'EOF'
*.exe
*.dll
*.so
*.dylib
/bin/
.env
.DS_Store
EOF
# 建立 README
cat > README.md << 'EOF'
# MyApp
專案說明
EOF
echo "專案結構建立完成!"
範例 3:本地依賴開發
假設你在同時開發兩個專案:
workspace/
├── myapp/ # 主專案
└── mylib/ # 函式庫專案
在 myapp/go.mod 中使用本地版本:
module github.com/username/myapp
go 1.21
require github.com/username/mylib v1.0.0
replace github.com/username/mylib => ../mylib
這樣修改 mylib 時,myapp 會立即使用最新版本。
最佳實踐
1. 專案結構
✅ 推薦:
- 小型專案:扁平結構(所有 .go 檔在根目錄)
- 中型專案:使用
cmd/、internal/、pkg/ - 大型專案:完整的標準結構
❌ 避免:
- 過度設計簡單專案
- 不一致的命名規則
2. 依賴管理
✅ 推薦:
# 定期整理依賴
go mod tidy
# 使用精確版本
go get github.com/gin-gonic/gin@v1.9.1
# 驗證依賴完整性
go mod verify
❌ 避免:
- 手動編輯
go.sum - 使用
latest在生產環境
3. 版本控制
✅ 應該提交:
go.modgo.sum.gitignore
❌ 不應該提交:
vendor/(除非有特殊需求)- 執行檔
.env檔案
4. 建構與部署
# 開發階段
go run main.go
# 測試
go test ./...
# 建構
go build -o bin/myapp
# 生產建構(最佳化)
CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o bin/myapp
5. 環境配置
# 設定國內代理(加速下載)
go env -w GOPROXY=https://goproxy.cn,direct
# 設定私有倉庫(跳過代理)
go env -w GOPRIVATE=github.com/mycompany/*
指令速查表
| 指令 | 說明 | 常用選項 |
|---|---|---|
go mod init |
初始化模組 | |
go mod tidy |
整理依賴 | |
go mod vendor |
建立 vendor | |
go get |
新增依賴 | -u 更新 |
go build |
建構 | -o 輸出檔名 |
go run |
執行 | |
go test |
測試 | -v 詳細, -cover 覆蓋率 |
go fmt |
格式化 | |
go vet |
靜態分析 | |
go install |
安裝工具 | |
go clean |
清理 | -cache 清理快取 |
常見問題
問題 1:go.mod 和 go.sum 有什麼差別?
| 檔案 | 用途 | 內容 |
|---|---|---|
go.mod |
定義依賴 | 模組路徑、版本需求 |
go.sum |
驗證依賴 | 加密雜湊值 |
問題 2:何時使用 go get vs go install?
# go get - 新增/更新依賴到當前專案
go get github.com/gin-gonic/gin
# go install - 安裝工具到 $GOPATH/bin
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
問題 3:internal/ 和 pkg/ 有什麼差別?
internal/ ← 只能被本專案使用(Go 編譯器強制)
pkg/ ← 可以被外部專案 import
問題 4:如何更新所有依賴到最新版本?
# 更新所有依賴
go get -u ./...
# 整理
go mod tidy
# 驗證
go test ./...
問題 5:如何處理依賴衝突?
# 檢視依賴關係
go mod graph | grep problematic-package
# 使用 replace 指定版本
# 在 go.mod 中:
replace github.com/problematic/package => github.com/problematic/package v1.2.3
總結
核心要點
-
專案結構:
- 小專案:扁平結構
- 大專案:
cmd/、internal/、pkg/分離
-
重要檔案:
go.mod:定義模組和依賴go.sum:驗證依賴完整性
-
常用指令:
go mod tidy:整理依賴(最常用)go build:建構執行檔go test:執行測試
工作流程
# 1. 初始化
go mod init github.com/username/myproject
# 2. 開發
go run main.go
# 3. 新增依賴
go get github.com/some/package
# 4. 整理
go mod tidy
# 5. 測試
go test ./...
# 6. 建構
go build -o myapp
建立日期:2025-11-03 最後更新:2025-11-18