Go 專案結構與指令完全指南

深入理解 Go 專案的目錄結構、重要檔案(go.mod、go.sum)以及常用 Go 指令


目錄


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.0v1.0.1:修復 bug
  • v1.0.0v1.1.0:新增功能
  • v1.9.9v2.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.modgo.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.mod
  • go.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.modgo.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

總結

核心要點

  1. 專案結構

    • 小專案:扁平結構
    • 大專案:cmd/internal/pkg/ 分離
  2. 重要檔案

    • go.mod:定義模組和依賴
    • go.sum:驗證依賴完整性
  3. 常用指令

    • 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

🔗相關文章