本章節涵蓋 Go 語言的基礎概念,包括工作區組態、原始碼組織、程式實體以及模組管理。
工作區與 GOPATH#
GOPATH 的角色#
GOPATH 是 Go 語言的工作區路徑,它決定了 Go 語言原始碼、編譯產物和可執行檔案的存放位置。
GOPATH 的值不能與 GOROOT(Go 安裝目錄)相同。GOPATH 可以包含多個路徑,在類 Unix 系統中使用冒號分隔,在 Windows 系統中使用分號分隔。
工作區目錄結構#
GOPATH/
├── src/ # 原始碼目錄
├── pkg/ # 編譯後的套件歸檔檔案 (.a)
└── bin/ # 可執行檔案src 目錄:存放所有 Go 原始碼檔案。原始碼的組織方式是以程式碼套件為基本單位,一個程式碼套件對應 src 目錄下的一個目錄。
pkg 目錄:存放編譯後的套件歸檔檔案(.a 檔案)。這些檔案按照平台架構組織,例如 linux_amd64、darwin_arm64 等。
bin 目錄:存放編譯後的可執行檔案。可以將此目錄加入系統 PATH 環境變數,方便直接執行命令。
套件匯入路徑範例
假設 GOPATH 為 /home/user/go,則:
/home/user/go/
└── src/
└── github.com/
└── username/
└── myproject/
├── main.go
└── utils/
└── helper.gomyproject的匯入路徑是github.com/username/myprojectutils套件的匯入路徑是github.com/username/myproject/utils
原始碼檔案分類#
Go 語言的原始碼檔案分為三種:命令源碼檔案、程式庫源碼檔案和測試源碼檔案。
命令源碼檔案#
命令源碼檔案是 Go 程式的入口點,具有以下特徵:
- 必須屬於
main套件(package main) - 必須包含無參數、無回傳值的
main函式
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}同一個程式碼套件中不能同時存在多個命令源碼檔案。如果違反此規則,執行
go build或go run時會報錯。
接收命令列參數#
使用 flag 套件處理命令列參數是 Go 的慣用做法:
package main
import (
"flag"
"fmt"
)
var name string
func init() {
// 定義命令列參數
flag.StringVar(&name, "name", "World", "使用者名稱")
}
func main() {
// 解析命令列參數
flag.Parse()
fmt.Printf("Hello, %s!\n", name)
}執行方式:
go run main.go -name="Go"
# 輸出: Hello, Go!flag 套件常用函式
| 函式 | 說明 |
|---|---|
flag.StringVar | 綁定字串類型參數到變數 |
flag.IntVar | 綁定整數類型參數到變數 |
flag.BoolVar | 綁定布林類型參數到變數 |
flag.Parse | 解析命令列參數 |
flag.Usage | 列印使用說明 |
程式庫源碼檔案#
程式庫源碼檔案用於封裝可重用的程式碼,供其他套件匯入使用。
// 檔案: utils/math.go
package utils
// Add 計算兩個整數的和(公開函式)
func Add(a, b int) int {
return a + b
}
// multiply 計算兩個整數的積(私有函式)
func multiply(a, b int) int {
return a * b
}Go 語言透過識別字首字母的大小寫來控制存取權限:
- 首字母大寫:公開(可被其他套件存取)
- 首字母小寫:私有(僅限當前套件存取)
internal 套件機制#
internal 目錄是 Go 的特殊機制,用於限制套件的可見範圍:
project/
├── internal/
│ └── secret/ # 僅 project 及其子套件可存取
│ └── config.go
└── main.go程式實體#
程式實體是 Go 語言中可以被命名的元素,包括變數、常數、函式和型別。
變數宣告#
Go 語言提供多種變數宣告方式:
// 標準宣告
var name string = "Go"
// 型別推斷
var version = "1.21"
// 短變數宣告(僅限函式內使用)
count := 10
// 多變數宣告
var (
width = 100
height = 200
)短變數宣告
:=只能在函式內部使用,但它更加簡潔。在套件層級宣告變數時,必須使用var關鍵字。
型別推斷規則#
// 整數字面量預設推斷為 int
x := 42 // int
// 浮點數字面量預設推斷為 float64
y := 3.14 // float64
// 字串字面量推斷為 string
s := "hello" // string
// 從已有變數推斷
var a int32 = 100
b := a // int32(繼承 a 的型別)型別轉換與型別斷言#
Go 是強型別語言,不同型別之間需要顯式轉換:
// 型別轉換(用於基本型別)
var i int = 42
var f float64 = float64(i)
// 型別斷言(用於介面型別)
var val interface{} = "hello"
// 安全的型別斷言
if str, ok := val.(string); ok {
fmt.Println("字串值:", str)
} else {
fmt.Println("不是字串型別")
}
// 型別 switch
switch v := val.(type) {
case string:
fmt.Println("字串:", v)
case int:
fmt.Println("整數:", v)
default:
fmt.Println("未知型別")
}變數重宣告規則#
在短變數宣告中,允許部分變數重宣告:
var err error
// 合法:n 是新變數,err 是重宣告
n, err := fmt.Println("hello")
// 合法:同一區塊中 err 被重新賦值
m, err := fmt.Println("world")變數重宣告必須滿足以下條件:
- 必須有至少一個新變數
- 重宣告的變數型別必須與原宣告一致
- 必須在同一個程式碼區塊中
程式碼區塊與作用域#
Go 語言有六種程式碼區塊,由小到大依次是:
- 語句區塊:if、for、switch 等語句的區塊
- 函式區塊:函式內部區域
- 套件區塊:當前套件的所有原始碼
- 檔案區塊:當前檔案的程式碼
- 匯入區塊:匯入的套件範圍
- 全域區塊:內建識別字(如 int、string、true 等)
package main
var global = "套件層級變數"
func main() {
local := "函式層級變數"
if true {
inner := "區塊層級變數"
fmt.Println(inner) // 可存取
}
// fmt.Println(inner) // 錯誤:inner 在此不可見
fmt.Println(local, global)
}變數遮蔽範例
內層區塊的變數會遮蔽外層同名變數:
package main
import "fmt"
var x = "全域"
func main() {
fmt.Println(x) // 輸出: 全域
x := "區域"
fmt.Println(x) // 輸出: 區域
if true {
x := "內層"
fmt.Println(x) // 輸出: 內層
}
fmt.Println(x) // 輸出: 區域
}Go Modules#
Go Modules 是 Go 語言官方的依賴管理解決方案,從 Go 1.11 開始引入,Go 1.16 後成為預設模式。
初始化模組#
# 建立新模組
go mod init github.com/username/myproject
# 這會建立 go.mod 檔案go.mod 檔案結構#
module github.com/username/myproject
go 1.21
require (
github.com/gin-gonic/gin v1.9.1
golang.org/x/sync v0.3.0
)
require (
// 間接依賴
github.com/bytedance/sonic v1.9.1 // indirect
)常用命令#
# 下載依賴
go mod download
# 整理依賴(移除未使用的,加入缺少的)
go mod tidy
# 檢視依賴關係圖
go mod graph
# 驗證依賴完整性
go mod verify
# 將依賴複製到 vendor 目錄
go mod vendor建議在專案根目錄執行
go mod tidy來自動整理依賴。這個命令會移除未使用的依賴,並加入程式碼中引用但 go.mod 中缺少的依賴。
版本選擇規則#
Go Modules 遵循語意化版本(Semantic Versioning)規範:
v1.2.3:主版本.次版本.修訂版本- 主版本 0 或 1 時,匯入路徑不變
- 主版本 2 及以上時,匯入路徑需加入版本後綴
import (
"github.com/user/pkg" // v0.x.x 或 v1.x.x
"github.com/user/pkg/v2" // v2.x.x
"github.com/user/pkg/v3" // v3.x.x
)go.sum 檔案說明
go.sum 檔案記錄所有依賴的加密雜湊值,用於驗證下載的模組是否被篡改:
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqFPSdI=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL8YrYN+...每個依賴會有兩行記錄:
- 第一行:模組內容的雜湊值
- 第二行:go.mod 檔案的雜湊值