為什麼需要開發自己的 Go 庫
在程式語言中,包(Package)和庫(Library)是程式碼組織和複用的重要工具。在 Go 中,包是程式碼的基本組織單位,每個 Go 程式都由包構成。包的作用是幫助組織程式碼,提供封裝和程式碼複用的機制。
Go 包可以包含函式、型別、變數和常量等,這些元素可以被其他包引用和使用。例如,Go 的標準庫提供了大量的包,如 net/http
包提供了 HTTP 客戶端和伺服器實現,fmt
包提供了格式化、I/O 函式等。
而庫是一種特殊的包,不包含 main
函式,不能被直接執行,但可以被其他程式引用。庫通常包含一些常用的功能或演算法,如字串處理、數學計算、網路通訊等。
開發自己的 Go 庫的優點:
- 複用性:當在多個專案中需要使用相同的功能時,可以將這些功能封裝在一個庫中,然後在需要的地方引用他。這樣可以避免重複編寫相同的程式碼,提高程式設計效率。
- 可維護性:當需要修改某個功能時,只需修改對應的庫,而不需要在多個地方進行修改,這樣可以使程式碼更易於理解和維護。
- 可測試性:為每個庫編寫單元測試,確保他們的功能正確。修改程式碼時,可以執行這些測試來檢查是否引入了新的錯誤。
接下來,將以 Asiatz(github.com/mazeyqian/asiatz)為例,詳細演示如何建立一個規範的 Go 庫。
Asiatz 主要功能是進行時區轉換,特別是對亞洲時區的處理,他能夠將各種時區轉換為 UTC 時間。
utcTime, err := asiatz.ShanghaiToUTC("08:00")
if err != nil {
// handle error
}
fmt.Println(utcTime) // Output: 00:00
第 1 步:建立目錄
在本地建立一個新的目錄,名為 asiatz
。這個目錄將包含所有的原始碼、測試和文件檔案。
mkdir asiatz
cd asiatz
第 2 步:初始化專案
2.1 初始化 Go 模組
在 asiatz
目錄下,執行 go mod init <domain>/<username>/<module-name>
來初始化 Go 模組。
go mod init github.com/mazeyqian/asiatz
專案結構:
asiatz
└── go.mod
2.2 建立檔案
建立一個新的 Go 檔案,名為 asiatz.go
。在此檔案中,定義一個名為 asiatz
的包,並編寫相對應的功能函式。
專案結構:
asiatz
├── asiatz.go
└── go.mod
程式碼示例:
package asiatz
import (
"fmt"
"strconv"
)
// ToUTC converts a time string (HH:mm) from a specified timezone to UTC time string (HH:mm).
func ToUTC(timezoneOffset float64, time string) (string, error) {
hour, err := strconv.Atoi(time[:2])
if err != nil {
return "", err
}
minute, err := strconv.Atoi(time[3:])
if err != nil {
return "", err
}
totalMinutes := hour*60 + minute
utcTotalMinutes := ((totalMinutes-int(timezoneOffset*60))%1440 + 1440) % 1440
utcHour := utcTotalMinutes / 60
utcMinute := utcTotalMinutes % 60
utcTime := fmt.Sprintf("%02d:%02d", utcHour, utcMinute)
return utcTime, nil
}
// ShanghaiToUTC converts a Shanghai time string (HH:mm) to UTC time string (HH:mm).
// For example, "08:00" in Shanghai is equivalent to "00:00" in UTC.
func ShanghaiToUTC(shanghaiTime string) (string, error) {
return ToUTC(8, shanghaiTime)
}
第 3 步:編寫測試
Go 提供了內建的測試框架,可以方便地編寫和執行測試用例,以確保程式碼的正確性和穩定性。
在 asiatz
目錄下建立一個新的 Go 檔案,名為 asiatz_test.go
。在這個檔案中編寫測試用例來測試 asiatz.go
中的函式。
專案結構:
asiatz
├── asiatz.go
├── asiatz_test.go
└── go.mod
程式碼示例:
package asiatz
import "testing"
type testConversion struct {
time string
expected string
}
var tests = map[string][]testConversion{
"Shanghai": {
{"01:00", "17:00"},
{"23:59", "15:59"},
},
// Others
}
func runConversionTests(t *testing.T, tests []testConversion, conversionFunc func(string) (string, error)) {
for _, test := range tests {
actual, err := conversionFunc(test.time)
if err != nil {
t.Errorf("Unexpected error for %s: %v", test.time, err)
continue
}
if actual != test.expected {
t.Errorf("Expected %s for %s but got %s", test.expected, test.time, actual)
}
}
}
func TestAllConversions(t *testing.T) {
for timezone, tests := range tests {
t.Run(timezone, func(t *testing.T) {
switch timezone {
case "Shanghai":
runConversionTests(t, tests, ShanghaiToUTC)
// Others
default:
t.Errorf("Unexpected timezone %s", timezone)
}
})
}
}
檢視完整的用例可見:github.com/mazeyqian/asiatz/blob/main/asiatz_test.go
在當前目錄下執行 go test
檢視結果:
PASS
ok github.com/mazeyqian/asiatz 0.449s
第 4 步:編寫文件
為了方便其他人理解和使用 Asiatz 庫,需要編寫相應的使用文件。文件應包括庫的目的、功能函式的用法、使用示例和注意事項等。
在 asiatz
目錄下,建立一個新的 README.md
檔案,並在其中編寫文件。
專案結構:
asiatz
├── asiatz.go
├── asiatz_test.go
├── go.mod
└── README.md
文件示例:
第 5 步:釋出
5.1 上傳
將 Asiatz 庫上傳到 GitHub 或其他程式碼託管平臺,使其他人可以方便地獲取和使用。
go get github.com/mazeyqian/asiatz
5.2 版本控制
在 Git 倉庫上,還可以使用標籤來管理庫的不同版本。
git tag v1.0.0
git push origin v1.0.0
例如 Asiatz 目前有四個版本:v1.0.0
、v1.1.0
、v1.1.1
、v1.1.2
,分別可以用以下命令獲取:
go get github.com/mazeyqian/asiatz@v1.0.0
go get github.com/mazeyqian/asiatz@v1.1.0
go get github.com/mazeyqian/asiatz@v1.1.1
go get github.com/mazeyqian/asiatz@v1.1.2
第 6 步:在真實專案中使用
以 Go 專案 github.com/mazeyqian/go-gin-gee 為例,首先在專案目錄(go-gin-gee
)下執行命令 go get github.com/mazeyqian/asiatz
獲取 Asiatz 庫,然後引入使用即可:
// https://github.com/mazeyqian/go-gin-gee/blob/main/internal/api/controllers/schedules-controller.go
package controllers
import (
"log"
"github.com/mazeyqian/asiatz"
)
func Check() {
// ...
utcTime, err := asiatz.ShanghaiToUTC("10:00")
if err != nil {
// handle error
}
log.Println("UTC Time:", utcTime) // Output: 02:00
// ...
}
總結
本文以 Asiatz 庫為例,詳細演示瞭如何從零開始建立、測試併發布自己的 Go 庫。無論是新手,還是有經驗的開發者;動手實踐,開發併發布自己的庫,不僅可以提高程式碼的複用性和維護性,提高自己的技能,還可以為社群做出貢獻。
版權宣告
本部落格所有的原創文章,作者皆保留版權。轉載必須包含本宣告,保持本文完整,並以超連結形式註明作者後除和本文原始地址:https://blog.mazey.net/4150.html
(完)