詳解如何在golang項目開發(fā)中創(chuàng)建自己的Module
為什么要創(chuàng)建一個 Module?
我們?nèi)粘i_發(fā)程序的時候都會引入第三方的 package,使用第三方的 package 的好處是我們可以快速的開發(fā)我們的程序的功能,只需要專注我們自己項目的功能,而且第三方的 package 提供了強大的,豐富的功能模塊。比如 web 開發(fā)框架 gin, echo,微服務(wù)開發(fā)框架 go-micro、go-zero;權(quán)限控制:casbin,jwt: jwt-go, gorm:gorm, 存儲:minio , 編寫命令:cobra, 配置文件解析:viper,數(shù)據(jù)庫:mysql 等等。這些包都是以 module 的形式提供的服務(wù)。
在自己的團隊內(nèi)部同樣可以構(gòu)建自己的私有化的 module,工公司內(nèi)部的其他團隊使用。比如我們公司有三個項目組,都有一些共同的項目。所以我們有公共的 module 放到 gitlab 上面提供不同團隊的公共使用。同樣這樣也遵循了軟件設(shè)計的高內(nèi)聚低耦合的設(shè)計總則。將獨立的功能封轉(zhuǎn)為 module。
這樣做的好處是我們可以只實現(xiàn)一次共享使用,并不需要每個團隊中都各自實現(xiàn),同樣也會帶啦有好多弊端。
如何實現(xiàn)我們自己的 Module?
既然我們使用了很多開源的 module為我們的日常開發(fā)提供了很多的便捷性,那我們該如何實現(xiàn)自己的 module 來提供給團隊中使用,甚至可以開放到 gitlab 上面提供給所有人使用(取之于開源,饋與開源)。
通過一下步驟來實現(xiàn)一個其他人可以使用的 module
- 創(chuàng)建模塊:編寫一個小模塊,其中包含可以從另一個模塊調(diào)用的函數(shù)。
- 從另一個模塊調(diào)用您的代碼:導(dǎo)入并使用您的新模塊。
- 返回并處理錯誤: 添加簡單的錯誤處理。
- 處理切片中的數(shù)據(jù)(Go 的動態(tài)大小數(shù)組)。
- 添加測試程序:使用 Go 的內(nèi)置單元測試功能來測試您的代碼。
創(chuàng)建一個 module 目錄
首先創(chuàng)建一個 Go 模塊。在模塊中,我們可以將一組有用的功能在一個或多個相關(guān)包中實現(xiàn)。
Go 代碼被分組為 package,package 又被分組為module。module 中需要指定運行代碼所需的依賴項,包括 Go 版本及其所需的其他模塊。
1、打開控制臺并cd轉(zhuǎn)到工作目錄中,并創(chuàng)建目錄module/greetings:
?mkdir module ?cd module/greetings/
2、go mod init命令初始化模塊 。
運行go mod init命令,為其提供模塊路徑 - 此處使用example.com/greetings. 如果發(fā)布模塊,則這必須是 Go 工具可以下載您的模塊的路徑。那將是我們的代碼的存儲庫。
?$ go mod init example.com/greetings
該go mod init命令創(chuàng)建一個 go.mod 文件來跟蹤代碼的依賴項。當(dāng)我們添加依賴項時,go.mod 文件將列出項目的代碼所依賴的版本。這可以保持構(gòu)建的可重復(fù)性,并讓我們可以直接控制要使用的模塊版本。
3、打開編輯器在greetings創(chuàng)建目錄下創(chuàng)建 文件greetings.go并編寫代碼:
?package greetings
??
?import (
? "fmt"
? "math/rand"
?)
?func Hello(name string) string {
? return fmt.Sprintf("嗨,%v。歡迎!", name)
?}該函數(shù)Hello 接受一個name類型為的參數(shù) string。該函數(shù)還返回一個string。在Go中,名稱以大寫字母開頭的函數(shù)可以被不在同一包中的函數(shù)調(diào)用。這在 Go 中稱為導(dǎo)出名稱。
從另一個模塊調(diào)用您的代碼
1、我們在 greeting 的同級目錄創(chuàng)建 hello 目錄,作為調(diào)用者。
?~/Developer/module ?tree -d ?. ?├── greetings ?└── hello
2、打開編輯器并創(chuàng)建文件 hello.go 文件。在 hello.go 文件中編寫代碼:
?import (
? "example.com/greetings"
? "log"
?)
??
?func main() {
? message := greetings.Hello("demo007")
? ?fmt.Println(message)
?}在文件中聲明一個main包。在 Go 中,作為應(yīng)用程序執(zhí)行的代碼必須位于包中main。
導(dǎo)入兩個包:example.com/greetings和fmt。 導(dǎo)入 example.com/greetings可以訪問該Hello 函數(shù)。還可以導(dǎo)入fmt, 以及處理輸入和輸出文本的函數(shù)(例如將文本打印到控制臺)。greetings通過調(diào)用包的 函數(shù) 來獲取輸出信息。
3、編輯example.com/hello模塊以使用本地 example.com/greetings模塊。
example.com/greetings 對于生產(chǎn)使用, 可以從其存儲庫發(fā)布模塊,Go 工具可以在其中找到它并下載它。但是由于我們尚未發(fā)布該模塊,因此我們需要調(diào)整該模塊,以便它可以在本地文件系統(tǒng)上 example.com/hello找到代碼example.com/greetings。
所以我們使用go mod edit命令編輯example.com/hello 模塊,將 Go 工具從其模塊路徑(模塊所在的位置)重定向到本地目錄(模塊所在的位置)。
在 hello 目錄中的命令提示符下,運行以下命令:
?$ go mod edit -replace example.com/greetings=../greetings
該命令指定example.com/greetings應(yīng)替換為../greetings以便查找依賴項。運行命令后,hello 目錄中的 go.mod 文件應(yīng)包含一條replace的指令。
?module example.com/hello ?? ?go 1.20 ?? ?replace example.com/greetings => ../greetings ?? ?require example.com/greetings v0.0.0-00010101000000-000000000000 ??
然后我們在命令中 cd hello 的目錄中,并執(zhí)行命令 go mod tidy, 執(zhí)行完成后我們發(fā)現(xiàn)新增加一行 require example.com/greetings v0.0.0-00010101000000-000000000000 并制定了一個版本號.
我們在 hello 中執(zhí)行運行命令查看:
?go run hello.go ?嗨,demo007。歡迎!
返回并處理錯誤
處理錯誤是可靠代碼的一個基本特征。下面我們將添加一些代碼以從 greetings 模塊返回錯誤,然后在調(diào)用者中處理它。
在 greetings/greetings.go 中,修改代碼:
?package greetings
??
?import (
? "errors"
? "fmt"
? "math/rand"
?)
??
?func Hello(name string) (string, error) {
? // 如果沒有提供名稱,則返回帶有錯誤消息的錯誤。
? if name == "" {
? return name, errors.New("empty name")
? }
??
? // 使用隨機格式創(chuàng)建一條消息。
? message := fmt.Sprintf("嗨,%v。歡迎!", name)
? return message, nil
?}我們修改了 Hello 函數(shù)添加了返回值 error,if 語句來檢測輸入的 name 是否是一個有效的值。如果為空則返回name 和 一個 錯誤 errors.New("empty name")
在 hello/hello.go 文件中,處理函數(shù)現(xiàn)在返回的錯誤 Hello以及非錯誤值。
?package main
??
?import (
? "example.com/greetings"
? "fmt"
? "log"
?)
??
?func main() {
? message, err := greetings.Hello("demo007")
? if err != nil {
? log.Fatal(err)
? }
? fmt.Println(message)使用標(biāo)準(zhǔn)庫中的函數(shù)log package輸出錯誤信息。如果出現(xiàn)錯誤,可以使用 log包的Fatal來打印錯誤并停止程序。
在目錄中的命令行中hello,運行 hello.go 以確認(rèn)代碼有效
?go run hello.go ?Great to see you, demo007!
處理切片中的數(shù)據(jù)
我們將使用 Go 切片。切片類似于數(shù)組,只不過它的大小會隨著添加和刪除項目而動態(tài)變化。切片是 Go 最有用的類型之一。
我們將添加一個小切片來包含三條問候消息,然后讓代碼隨機返回其中一條消息。
在 greetings/greetings.go 中,我們修改代碼,如下所示。
?package greetings
??
?import (
? "errors"
? "fmt"
? "math/rand"
?)
??
?func Hello(name string) (string, error) {
? // 如果沒有提供名稱,則返回帶有錯誤消息的錯誤。
? if name == "" {
? return name, errors.New("empty name")
? }
??
? // 使用隨機格式創(chuàng)建一條消息。
? message := fmt.Sprintf(randomFormat(), name)
? return message, nil
?}
??
?func randomFormat() string {
? formats := []string{
? "Hi, %v. Welcome!",
? "Great to see you, %v!",
? "Hail, %v! Well met!",
? }
? return formats[rand.Intn(len(formats))]
?}1、添加一個randomFormat函數(shù),返回隨機選擇的問候消息格式。 randomFormat以小寫字母開頭,使其只能被其自己的包中的代碼訪問(換句話說,它不會被導(dǎo)出)。
2、在 中randomFormat,聲明formats具有三種消息格式的切片。聲明切片時,您可以在括號中省略其大小,如下所示:[]string。這告訴 Go 切片底層數(shù)組的大小可以動態(tài)更改。
3、使用該 math/rand 包生成一個隨機數(shù),用于從切片中選擇一個項目。
4、在 中Hello,調(diào)用該randomFormat函數(shù)來獲取您將返回的消息的格式,然后 name一起使用該格式和值來創(chuàng)建消息。
5、像以前一樣返回消息以及錯誤
在 hello/hello.go 中,我們修改代碼,如下所示:
?package main
??
?import (
? "example.com/greetings"
? "fmt"
? "log"
?)
??
?func main() {
? message, err := greetings.Hello("demo007x")
? // 如果返回了錯誤,請將其打印到控制臺并退出程序。
? if err != nil {
? log.Fatal(err)
? }
? //如果沒有返回錯誤,請將返回的消息打印到控制臺。
? fmt.Println(message)
?}
??我們運行代碼看看輸出的內(nèi)容:
go run hello.go
Hail, demo007x! Well met!
?
go run hello.go
Great to see you, demo007x!
?
go run hello.go
Hi, demo007x. Welcome!
測試 module
以上我們編寫了基本的或者說是最簡單的 golang module 的程序項目,如何確保我們的程序是無錯誤的或者是沒有 bug 的?最好的辦法就是添加 測試程序。
在開發(fā)過程中測試代碼可能會暴露出在您進行更改時出現(xiàn)的錯誤。
Go 對單元測試的內(nèi)置支持使我們可以更輕松地進行測試。具體來說,使用命名約定、Go 的testing包和go test命令,可以快速編寫和執(zhí)行測試。
在greetings目錄中,創(chuàng)建一個名為greetings_test.go的文件。
以 _test.go 結(jié)尾的文件名告訴
go test命令該文件包含測試函數(shù)。在greetings_test.go中,編寫以下代碼并保存文件:
?package greetings
??
?import (
? "regexp"
? "testing"
?)
??
?// TestHelloName 調(diào)用 greetings.Hello 并傳入一個名稱,檢查返回值是否有效。
?func TestHelloName(t *testing.T) {
? name := "Gladys"
? want := regexp.MustCompile(`\b` + name + `\b`)
? msg, err := Hello("Gladys")
? if !want.MatchString(msg) || err != nil {
? t.Fatalf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want)
? }
?}
??
?// TestHelloEmpty 調(diào)用 greetings.Hello 并傳入空字符串, 檢查是否出現(xiàn)錯誤。
?func TestHelloEmpty(t *testing.T) {
? msg, err := Hello("")
? if msg != "" || err == nil {
? t.Fatalf(`Hello("") = %q, %v, want "", error`, msg, err)
? }
?}創(chuàng)建兩個測試函數(shù)來測試該
greetings.Hello函數(shù)。測試函數(shù)名稱的形式為,其中Name表示有關(guān)特定測試的信息。此外,測試函數(shù)將指向包的指針作為參數(shù)。可以使用此參數(shù)的方法來報告和記錄測試。兩個測試:
TestHelloName調(diào)用該Hello函數(shù),傳遞一個name值,該函數(shù)應(yīng)該能夠返回有效的響應(yīng)消息。如果調(diào)用返回錯誤或意外響應(yīng)消息(不包含您傳入的名稱),則可以使用參數(shù)t的方法將消息打印到控制臺并結(jié)束執(zhí)行Fatalf。TestHelloEmptyHello使用空字符串調(diào)用該函數(shù)。此測試目的在確認(rèn)錯誤處理是否有效。如果調(diào)用返回非空字符串或沒有錯誤,則可以使用t參數(shù)的Fatalf方法將消息打印到控制臺并結(jié)束執(zhí)行。
在greetings目錄下的命令行中,運行命令 go test 執(zhí)行測試。
?go test -v ?=== RUN ? TestHelloName ?--- PASS: TestHelloName (0.00s) ?=== RUN ? TestHelloEmpty ?--- PASS: TestHelloEmpty (0.00s) ?PASS ?ok example.com/greetings 0.007s
通過測試輸出的結(jié)果可以看到我們的程序全部都通過了測試。
發(fā)布module
以上我們編寫了我們的第一個 go module, 并且編寫了對應(yīng)函數(shù)的測試程序,然后我們可以將我們的 module 程序提交到 github等系統(tǒng)。其他人就可以通過執(zhí)行命令 go get example.com/greetings 將 greeting 包安裝到自己的項目中。
總結(jié):
golang module 給我們提供了靈活的本地開發(fā)并測試 module 的機制。我們通過修改 go.mod 文件,通過指令 replace example.com/greetings => ../greetings 來實現(xiàn)本地 module 的開發(fā)和測試的全部過程。
以上就是詳解golang項目開發(fā)如何創(chuàng)建自己的Module的詳細(xì)內(nèi)容,更多關(guān)于golang創(chuàng)建Module的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Jenkins+K8s實現(xiàn)Go后端服務(wù)自動化部署教程
本文詳細(xì)介紹了使用Jenkins和Kubernetes(K8s)實現(xiàn)Go后端服務(wù)的自動化部署流程,涵蓋前期環(huán)境準(zhǔn)備、Jenkins流水線配置、K8s資源編排、部署驗證、常見問題排查以及相關(guān)技術(shù)拓展和優(yōu)化建議,旨在提升開發(fā)和運維效率,保障服務(wù)的高可用性2026-04-04
Go Excelize API源碼解讀GetSheetViewOptions與SetPageLayo
這篇文章主要為大家介紹了Go Excelize API源碼解讀GetSheetViewOptions與SetPageLayout方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08
golang 交叉編譯C++ dll配置文件的實現(xiàn)
本文探討了在64位環(huán)境下調(diào)用32位C++ DLL的的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-07-07

